专栏文章

霉利的题解(2)

P1342题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqmqagv
此快照首次捕获于
2025/12/04 07:19
3 个月前
此快照最后确认于
2025/12/04 07:19
3 个月前
查看原文
这道题我们可以发现可以分为两个部分。
  1. 第一是学生去车站的部分。(一点到多点,dij或spfa)
  2. 第二是学生从车站回来。(多点到一点)

我们如果可以将图反着存,那么就可以将多点到一点变成一点到多点。

代码如下
CPP
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+10;
ll n,m,x,y,l,dis[N],dis1[N],f[N],f1[N],pre[N],pre1[N],cnt,cnt1,q[5*N],q1[5*N],sum=0;//因为要有正反两图,所以我们要定义双份;
struct edge{
	ll f,t,l,n;
}a[5*N],b[5*N];
void add(ll x,ll y,ll l){
	a[++cnt].f=x;
	a[cnt].t=y;
	a[cnt].l=l;
	a[cnt].n=pre[x];
	pre[x]=cnt;
}//链式前向星(正图)
void add1(ll y,ll x,ll l){
	b[++cnt1].f=y;
	b[cnt1].t=x;
	b[cnt1].l=l;
	b[cnt1].n=pre1[y];
	pre1[y]=cnt1;
}//链式前向星(反图)
//正图spfa模版
void spfa(){
	ll head=1,tail=1;
	q[1]=1;
	f[1]=1;
	dis[1]=0;
	while(head<=tail){
		ll from=q[head];
		for(int i=pre[from];i;i=a[i].n){
			ll to=a[i].t;
			ll len=a[i].l;
			if(dis[from]+len<dis[to]){
				dis[to]=dis[from]+len;
				if(f[to]==0){
					f[to]=1;
					q[++tail]=to;
				}
			}
		}
		f[from]=0;
		head++;
	}
}
//反图spfa
void spfa1(){
	ll head=1,tail=1;
	q1[1]=1;
	f1[1]=1;
	dis1[1]=0;
	while(head<=tail){
		ll from=q1[head];
		for(int i=pre1[from];i;i=b[i].n){
			ll to=b[i].t;
			ll len=b[i].l;
			if(dis1[from]+len<dis1[to]){
				dis1[to]=dis1[from]+len;
				if(f1[to]==0){
					f1[to]=1;
					q1[++tail]=to;
				}
			}
		}
		f1[from]=0;
		head++;
	}
}
int main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%lld%lld%lld",&x,&y,&l);
		add(x,y,l);//正着存入
		add1(y,x,l);//反着存入
	}
	for(int i=1;i<=n;i++){
		dis[i]=2e9+10;
		dis1[i]=2e9+10;
	}//初始化
	spfa();
	spfa1();
	for(int i=2;i<=n;i++){
		sum+=dis[i]+dis1[i];//将所有的点费用加起来
	}
	printf("%lld",sum);
}
注意要用快读或者c的输入输出,不然只有小概率得满分(为了保险起见最好加上) 作者亲自实践:(

评论

0 条评论,欢迎与作者交流。

正在加载评论...