POJ-1511-Invitation Cards
http://poj.org/problem?id=1511
题意是给出一些边,求第一个点到其他各点距离之和+其他各点到第一个点的距离之和的最小值,求两次单源最短距离即可,第一次求出第一个点到其他各点距离的最小值,第二次将所有的有向边反向,再求一次第一个点到其他各点距离的最小值即是原图中其他各点到第一个点的最小距离,题目的数据比较多,用spfa
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define N 1000010
#define MAX 0x7fffffff
int head[N],nextt[N],key[N],num[N],visit[N];
int t;
__int64 dis[N];
int nodenum,edgenum;
struct cam //有向边
{
int st,ed;
int v;
}edge[N];
void add(int st,int ed,int v)
{
key[t]=v;
nextt[t]=head[st]; //以u为起点的上一条边
num[t]=ed;
head[st]=t++; //以st为起点最近的一条边
}
void init()
{
t=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=nodenum;i++)
dis[i]=MAX;
}
__int64 spfa(int start)
{
__int64 total=0;
int temp;
queue<int>q;
while(!q.empty())
q.pop();
memset(visit,0,sizeof(visit));
dis[start]=0;
visit[start]=1;
q.push(start);
while(!q.empty())
{
temp=q.front();
q.pop();
visit[temp]=0;
for(int i=head[temp];i!=-1;i=nextt[i])
{
if(dis[num[i]]>dis[temp]+key[i])
{
dis[num[i]]=dis[temp]+key[i];
if(!visit[num[i]])
{
q.push(num[i]);
visit[num[i]]=1;
}
}
}
}
for(int i=1;i<=nodenum;i++)
total+=dis[i];
return total;
}
int main()
{
int top,cas;
__int64 ans;
scanf("%d",&cas);
while(cas--)
{
top=ans=0;
scanf("%d%d",&nodenum,&edgenum);
init();
for(int i=0;i<edgenum;i++)
{
scanf("%d%d%d",&edge[top].st,&edge[top].ed,&edge[top].v);
add(edge[top].st,edge[top].ed,edge[top].v);
top++;
}
ans+=spfa(1);
init();
for(int i=0;i<top;i++)
add(edge[i].ed,edge[i].st,edge[i].v);
ans+=spfa(1);
printf("%I64d\n",ans);
}
return 0;
}