最短路
题目大意:给你n个顶点,m条有向边,求从起点1出发到各个顶点后再回到起点所需最小代价。
思路:存两张图,一张正着存,一张倒着存。然后分别在这两张图里跑spfa,把结果加起来就行啦!
倒着存从1开始跑,其实就是求从各个顶点到1的最小代价,再加上正着存的就是答案啦!
贴个代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 1000000
using namespace std;
struct edge{
int next;
int to;
int dis;
};
int h1[MAXN+5],h2[MAXN+5];
int que[2*MAXN+5];
long long dis1[MAXN+5],dis2[MAXN+5];
bool f[MAXN+5];
int t,n,m,k,u,v,d;
edge ed1[MAXN+5],ed2[MAXN+5];
void read(int x,int y,int z){
k++;
ed1[k].next=h1[x]; ed1[k].to=y; ed1[k].dis=z; h1[x]=k;
ed2[k].next=h2[y]; ed2[k].to=x; ed2[k].dis=z; h2[y]=k;
}
void spfa111(){
memset(dis1,0x7f,sizeof(dis1));
memset(f,false,sizeof(f));
int r=0,w=1;
que[1]=1; f[1]=true; dis1[1]=0;
while (r!=w){
r=(r+1)%MAXN;
int x=que[r];
f[x]=false;
for (int i=h1[x];i;i=ed1[i].next)
if (dis1[ed1[i].to]>dis1[x]+ed1[i].dis){
dis1[ed1[i].to]=dis1[x]+ed1[i].dis;
if (!f[ed1[i].to]){
w=(w+1)%MAXN;
que[w]=ed1[i].to;
f[ed1[i].to]=true;
}
}
}
}
void spfa222(){
memset(dis2,0x7f,sizeof(dis2));
memset(f,false,sizeof(f));
int r=0,w=1;
que[1]=1; f[1]=true; dis2[1]=0;
while (r!=w){
r=(r+1)%MAXN;
int x=que[r];
f[x]=false;
for (int i=h2[x];i;i=ed2[i].next)
if (dis2[ed2[i].to]>dis2[x]+ed2[i].dis){
dis2[ed2[i].to]=dis2[x]+ed2[i].dis;
if (!f[ed2[i].to]){
w=(w+1)%MAXN;
que[w]=ed2[i].to;
f[ed2[i].to]=true;
}
}
}
}
int main(){
scanf("%d",&t);
while (t--){
memset(h1,0,sizeof(h1));
memset(h2,0,sizeof(h2));
k=0;
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&d);
read(u,v,d);
}
spfa111();
spfa222();
long long ans=0;
for (int i=1;i<=n;i++)
ans=ans+dis1[i]+dis2[i];
printf("%lld\n",ans);
}
return 0;
}