spfa算法
用vector 写得邻接表 会 TLE,只好用静态邻接表
spfa求出1点到各个点的 最小距离,,图 反着存,用spfa 就能求出 各个点到1点的最小距离。。(好神奇!)
first[i] 数组 存 i点连出的边的最后一条边的编号 例如有图:(1)1---3, (2) 2---3,(3) 3----4, (4)1-----4, 一共4条边,最终first[1] = 4; first[2]=2; first[3]=3; first[4] = -1;
nex[i]数组用来遍历,他能 遍历与i点相连的所有的边,从 最后一条边 开始的遍历;
p[i] 存的是所有的边
自己画图,领悟一下吧!!
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
using namespace std;
struct node{
int a,b,len;
}p1[1000050],p2[1000050];
int n;
__int64 dis[1000050];
__int64 dis1[1000050];
int first1[1000050],first2[1000050],nex1[1000050],nex2[1000050];
int f[1000050];
void spfa()
{
for(int i=0;i<=n;i++)
{
dis[i]=2000000100;
f[i]=0;
}
queue<int> qu;
while(!qu.empty())
qu.pop();
dis[1]=0;
f[1]=1;
qu.push(1);
while(!qu.empty())
{
int t=qu.front();
qu.pop();
for(int i=first1[t];i!=-1;i=nex1[i]){
int b=p1[i].b;
if(dis[t]+p1[i].len < dis[b]){
dis[b]=dis[t]+p1[i].len;
if(f[b]==0){
qu.push(b);
f[b]=1;
}
}
}
f[t]=0;
}
}
void spfa1() //spfa算法
{
for(int i=0;i<=n;i++)
{
dis1[i]=1000000100;
f[i]=0;
}
queue<int> qu;
while(!qu.empty())
qu.pop();
dis1[1]=0;
f[1]=1;
qu.push(1);
while(!qu.empty())
{
int t=qu.front();
qu.pop();
for(int i=first2[t];i!=-1;i=nex2[i]){ // 用邻接表搜索
int b=p2[i].b;
if(dis1[t]+p2[i].len < dis1[b]){
dis1[b]=dis1[t]+p2[i].len;
if(f[b]==0){
qu.push(b);
f[b]=1;
}
}
}
f[t]=0;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int m,i,j,k;
__int64 sum=0;
memset(first1,-1,sizeof(first1));
memset(first2,-1,sizeof(first2));
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
int t1,t2,t3;
scanf("%d%d%d",&t1,&t2,&t3);
p1[i].a=t1;
p1[i].b=t2;
p1[i].len=t3;
p2[i].a=t2;
p2[i].b=t1;
p2[i].len=t3;
nex1[i]=first1[p1[i].a]; //静态 邻接表的 精华啊!!
first1[p1[i].a]=i; //静态 邻接表的 精华啊!!
nex2[i]=first2[p2[i].a];
first2[p2[i].a]=i;
}
spfa1();
for(i=2;i<=n;i++)
sum+=dis1[i];
spfa();
for(i=2;i<=n;i++)
sum+=dis[i];
printf("%I64d\n",sum);
}
return 0;
}