题目链接http://poj.org/problem?id=1511
题意:
在一个有向图中,求从源点出发到达所有点,再返回源点的总花费。其实所有点的往返路径的最小值的和。
思路:
普通的往返路径类题目可以直接转置邻接矩阵,但是这道题的点比较多,我们需要采用邻接表的形式存储图。但通过邻接表建立反向图的过程又比较复杂,所以我们直接在输入的时候分别建立两个不同方向的图。然后使用 SPFA 算法计算最短路径,网上有 dalao 说堆优化的 Dijstra 算法也可以通过此题,在此只贴出 SPFA 算法,本代码中使用 vector 实现邻接表,但使用数组实现邻接表会更加高效。
#include <cstdio>
#include <vector>
#include <queue>
#include <iostream>
#define N 1000005
#define E 1000005
#define INF int(1e10)
#define fp(_p,_q,_r) for(int _p=_q;_p<_r;_p++)
using namespace std;
int ro,n,e;
struct edge{
int v,c;
edge(int a=0,int b=0):v(a),c(b){};
};
typedef vector <edge> T;
T G0[N];
T G1[N];
int d0[N],d1[N];
bool inq[N];
void spfa(int s,T * G,int * d){
fill(inq,inq + N,0);
fill(d,d + N,INF);
inq[s] = 1;
d[s] = 0;
queue <int> q;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
inq[u] = 0;
fp(i,0,G[u].size()){
int v = G[u][i].v;
if(d[v] > d[u] + G[u][i].c){
d[v] = d[u] + G[u][i].c;
if(!inq[v]){
inq[v] = 1;
q.push(v);
}
}
}
}
}
int main(void)
{
scanf("%d",&ro);
fp(i,0,n){
G0[i].reserve(N);
G1[i].reserve(N);
}
while(ro --){
fp(i,0,n){
G0[i].resize(0);
G1[i].resize(0);
}
scanf("%d%d",&n,&e);
fp(i,0,e){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
G0[-- a].push_back(edge(-- b,c));
G1[b].push_back(edge(a,c));
}
spfa(0,G0,d0);
spfa(0,G1,d1);
long long res = 0;
fp(i,1,n){
res += d0[i] + d1[i];
}
printf("%lld\n",res);
}
return 0;
}