【题目链接】
http://poj.org/problem?id=1511
题目意思
给n个点,m条有向边。问你从1到其他n-1各点的最短路和加上从n-1各点到1的最短路。
解题思路
因为是有向边而且一次终点在1,一次起点在1,所以只要跑一遍正的图在跑遍反的地图,总和就是要的答案。
坑点在于数据比较大总和要用long long,邻接表开两个时间就会wa,要用优先队列优化。
代码部分
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <string>
#include <map>
using namespace std;
#define LL long long
#define inf 0x3f3f3f3f
const int N = 1e6+5;
LL dis[N]; ///存储正向最短路
int vis[N]; ///记录是否在队列
int k,n;
struct node
{
int v;
LL w;
friend bool operator < (node a,node b)
{
return a.w>b.w;
}
}s;
struct edge
{
int u,v,w;
}eg[N];
vector<vector<node> >m(N);
void init ()
{
for (int i = 1; i <= n; i++)
{
dis[i] = inf;
vis[i] = 0;
}
}
node add (int v,LL w) ///转换成node类型
{
node t;
t.v = v;
t.w = w;
return t;
}
void spfa()
{
init();
priority_queue<node>q;
q.push(add(1,0));
vis[1] = 1;
dis[1] = 0;
while (!q.empty())
{
node t = q.top();
q.pop();
for (int i = 0; i < m[t.v].size();i++)
{
s = m[t.v][i];
if (dis[s.v] > dis[t.v]+s.w) ///松弛
{
dis[s.v] = dis[t.v]+s.w;
if (!vis[s.v]) ///判断是否在队列
{
q.push(add(s.v,dis[s.v]));
vis[s.v] = 1;
}
}
}
vis[t.v] = 0;
}
}
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
LL ans = 0;
scanf("%d %d",&n,&k);
for (int i = 1; i<= n; i++)
{
m[i].clear();
}
for(int i =0; i < k;i++)
{
int v,u,w;
scanf("%d %d %d",&eg[i].u,&eg[i].v,&eg[i].w);
m[eg[i].u].push_back(add(eg[i].v,eg[i].w));
}
spfa();
for (int i = 1;i<= n ;i++) /// 求和并清除图
{
ans += dis[i];
m[i].clear();
}
for (int i = 0; i <= k; i++) ///构造方向图
{
m[eg[i].v].push_back(add(eg[i].u,eg[i].w));
}
spfa();
for (int i = 1; i <= n; i++)
ans += dis[i];
printf("%lld\n",ans);
}
return 0;
}