yzoj P1412 & 洛谷P1629 邮递员送信 题解

有一个邮递员要送东西,邮局在结点1。他总共要送N-1样东西,其目的地分别是2~N。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要一定的时间。这个邮递员每次只能带一样东西。求送完这N-1样东西并且最终回到邮局最少需要多少时间。

很容易发现我们要求 \(\sum_{j=1}^n\) dis[1][ j ]+dis[ j ][1],可以想到跑spfa,对于dis[1][ j ]可以一遍spfa解决但是对于 dis[ j ][1]却不好解决,如果跑n遍spfa明显超时,但我们可以换个思路,建立反图,对节点1跑spfa,那么1节点到别的点的距离就是别的点到1节点的距离。

代码

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
const int N=1010,M=100010;
int head[N][2],ver[M][2],edge[M][2],Next[M][2],d[N][2];
int n,m,tot1,tot2;
long long ans;
bool v[N];
queue<int> q;
void add(int x,int y,int z){
	ver[++tot1][0]=y;edge[tot1][0]=z;Next[tot1][0]=head[x][0],head[x][0]=tot1;
}
void add1(int x,int y,int z){
	ver[++tot2][1]=y;edge[tot2][1]=z;Next[tot2][1]=head[x][1],head[x][1]=tot2;
}
void spfa(){
	memset(d,0x3f,sizeof(d));
	d[1][0]=0,v[1]=1;
	q.push(1);
	while(q.size()){
		int x=q.front();q.pop();
		v[x]=0;
		for(int i=head[x][0];i;i=Next[i][0]){
			int y=ver[i][0],z=edge[i][0];
			if(d[y][0]>d[x][0]+z){
				d[y][0]=d[x][0]+z;
				if(!v[y]) q.push(y),v[y]=1;
			}
		}
	}
	while(!q.empty()) q.pop();
	memset(v,0,sizeof(v));
	d[1][1]=0,v[1]=1;
	q.push(1);
	while(q.size()){
		int x=q.front();q.pop();
		v[x]=0;
		for(int i=head[x][1];i;i=Next[i][1]){
			int y=ver[i][1],z=edge[i][1];
			if(d[y][1]>d[x][1]+z){
				d[y][1]=d[x][1]+z;
				if(!v[y]) q.push(y),v[y]=1;
			}
		}
	}
}
int main(){
	n=read();m=read();
	for(int i=1;i<=m;++i){
		int x,y,z;
		x=read();y=read();z=read();
		add(x,y,z);
		add1(y,x,z);
	}
	spfa();
	for(int i=1;i<=n;++i){
		ans+=d[i][0]+d[i][1];
	}
	printf("%lld",ans);
	return 0;
}
posted @ 2019-08-27 10:09  End_donkey  阅读(223)  评论(0编辑  收藏  举报