题目连接:http://poj.org/problem?id=1511
题意:
有一个N个点的有向图从1~N,求从1号点到所有点的最短距离和+从所有点到1号点的最短距离。
分析:
利用SPFA求出1号点到其他点的单源最短路径,将方向逆转求出其他点到1号点的最短路,枚举相加即可。
参考博客:https://blog.csdn.net/u013480600/article/details/37812835
代码:
//POJ1511题用到,用邻接表实现,避免了vector添加边信息的时间消耗
#include<algorithm>
#include<vector>
#include<queue>
#include<cstring>
#include<cstdio>
#define INF 1e9
#define LL long long
using namespace std;
const int maxn =1000000+10;
int n,m;
struct Edge
{
int from,to,dist;
Edge(){}
Edge(int f,int t,int d):from(f),to(t),dist(d){}
};
struct BellmanFord
{
int n,m;
int head[maxn]; //每个节点邻接表的头
int next[maxn];
Edge edges[maxn]; //所有的边信息
bool inq[maxn];
int d[maxn];
int p[maxn];
int cnt[maxn];
void init(int n)
{
this->n=n;
this->m=0;
memset(head,-1,sizeof(head));///邻接表初始化
}
void AddEdge(int from,int to,int dist)///加入一条边
{
edges[m]=Edge(from,to,dist);
next[m]=head[from];///next[m]存储的是“编号为m的边”的“前一条边”的编号。
head[from] = m++;///记录此条边的编号
}
bool negativeCycle(int s)
{
queue<int> Q;
memset(inq,0,sizeof(inq));
memset(cnt,0,sizeof(cnt));
for(int i=0;i<n;i++) d[i]= i==s?0:INF;
Q.push(s);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
inq[u]=false;
for(int i=head[u];i!=-1;i=next[i])
{
Edge &e=edges[i];
if(d[e.to] > d[u]+e.dist)
{
d[e.to] = d[u]+e.dist;
p[e.to] = i;
if(!inq[e.to])
{
inq[e.to]=true;
Q.push(e.to);
if(++cnt[e.to]>n) return true;
}
}
}
}
return false;
}
}BF1,BF2;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
BF1.init(n);BF2.init(n);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
u--;v--;
BF1.AddEdge(u,v,w);
BF2.AddEdge(v,u,w);
}
BF1.negativeCycle(0);//加边后在判断
BF2.negativeCycle(0);
LL ans=0;
for(int i=1;i<n;i++)//注意是从1到n-1,
{
ans+=(BF1.d[i]+BF2.d[i]);
}
printf("%lld\n",ans);
}
return 0;
}