题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1535
题目大意:P个点和Q条有向边,求所有点到源点1的来回最短路之和
因为题目数据太大,所以用SPFA,因为点太多,也需用邻接表建图,同时邻接表不能用vector,会超内存
先正向建图,求源点1到所有点距离和;
再反向建图,求源点1到所有点距离和;
相加即为答案。
数据要用__int64
/*
Memory 43524 KB
Time 1343 ms
*/
#include<iostream>
#include<cstdio>
#include<climits>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
#define N 1000100
#define INF INT_MAX>>1
#define ll __int64
struct {
int v,w,next;//终点,长度
}edge[N];
int v,e; //点,边
ll dis[N];
int vis[N];
ll path[N][3];
queue<int> q;
int node;
int headlist[N];
void Init(){
int i,j;
node=1;
for(i=1;i<=v;++i){
dis[i]=INF;
}
memset(vis,0,sizeof(vis));
memset(headlist,0,sizeof(headlist));
}
void add_edge(int u,int v,int w){
edge[node].v=v;
edge[node].w=w;
edge[node].next=headlist[u];
headlist[u]=node++;
}
void SPFA(int src)
{
int i,j;
while(!q.empty()) q.pop();
dis[src]=0;
vis[src]=1;
q.push(src);
while(!q.empty())
{
int cur=q.front();
q.pop();
vis[cur]=0;//出队标记为0
for(i=headlist[cur];i;i=edge[i].next)
{
if(dis[edge[i].v]>dis[cur]+edge[i].w)
{
dis[edge[i].v]=dis[cur]+edge[i].w;//能松弛就松弛
if(!vis[edge[i].v])//不在队列中则加入,然后更新所有以前经过此点的最短路径
{
q.push(edge[i].v);
vis[edge[i].v]=1;
}
}
}
}
}
void Add(){
int i;
for(i=0;i<e;++i)
{
scanf("%I64d%I64d%I64d",&path[i][0],&path[i][1],&path[i][2]);
}
}
void Solve(){
int i;
ll ans=0;
Init();
for(i=0;i<e;++i)
{
add_edge(path[i][0],path[i][1],path[i][2]);
}
SPFA(1);
for(i=1;i<=v;++i){
ans+=dis[i];
}
Init();
for(i=0;i<e;++i)
{
add_edge(path[i][1],path[i][0],path[i][2]);
}
SPFA(1);
for(i=1;i<=v;++i){
ans+=dis[i];
}
printf("%I64d\n",ans);
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&v,&e);
Add();
Solve();
}
return 0;
}