有一个邮递员要送东西,邮局在结点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;
}