题目信息:点击打开链接
题解:题目大意:就是有一个原点,还有很多除原点外的点,保证原点可以到任何点,求原点到所有点再从所有点回到原点的最小距离。
我的思路:其实这就相当于两遍最短路,第一遍是原点到各个点,第二遍是各个点到原点,不能单纯的一遍最短路然后乘2,那就说明你真的很二,出题人有那么无聊吗?动脑子想想好不好。关于第二步各个点到原点,我们可以反向存图,再从原点往各个点跑一遍。
下面是代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<iostream>
#include<queue>
#include<map>
#include<climits>
#include<cmath>
#define ll long long
using namespace std;
const int maxn = 1e6+10;
int N, M, vis[maxn], head[2][maxn], cnt, dis[maxn];
struct node
{
int u, v, w;
int next;
}edge[2][maxn];
void update(int u, int v, int w)
{
edge[0][cnt].u = u, edge[0][cnt].v = v, edge[0][cnt].w = w;
edge[0][cnt].next = head[0][u];
head[0][u] = cnt;
edge[1][cnt].u = v, edge[1][cnt].v = u, edge[1][cnt].w = w;
edge[1][cnt].next = head[1][v];
head[1][v] = cnt++;
}
ll SPFA(int flag)
{
queue<int> q;
memset(vis, 0, sizeof(vis));
memset(dis, -1, sizeof(dis));
q.push(1);
vis[1] = 1;
dis[1] = 0;
while(!q.empty())
{
int h = q.front();
q.pop();
vis[h] = 0;
for(int i = head[flag][h]; i!=-1; i = edge[flag][i].next)
{
int u = edge[flag][i].u, v = edge[flag][i].v, w = edge[flag][i].w;
if(dis[v] == -1 || dis[v] > dis[u]+w)
{
dis[v] = dis[u]+w;
if(!vis[v]) // 记录在队列里面的顶点
{
vis[v] = 1;
q.push(v);
}
}
}
}
ll ans = 0;
for(int i = 1; i <= N; i++)
ans += dis[i];
return ans;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &N, &M);
cnt = 0;
memset(head, -1, sizeof(head));
int x1, x2, x3;
for(int i = 1; i <= M; i++)
{
scanf("%d%d%d", &x1, &x2, &x3);
update(x1, x2, x3);
}
ll ans;
ans = SPFA(1)+SPFA(0);
printf("%lld\n", ans);
}
}