第一反应想到和 poj3268做法一样,先是从起点dj,然后将图反向,再次dj一次,求和即可。但是,数据O(n*n)过不去,所以需要使用dijkstra的堆优化!
淦,没用scanf结果超时了= =
#pragma warning(disable:4996)
#include<iostream>
#include<string>
#include<cmath>
#include<ctype.h>
#include<memory.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<iomanip>
#include<set>
#include<list>
#include<vector>
#include<stack>
#include<queue>
#define ll long long int
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1000010;
int n, m;//p/n个点,q/m条边
int cnt = 0;
int T;
int head[maxn];
int a[maxn][3];
ll dis[maxn];
int vis[maxn];
struct EDGE
{
int u, v, w;
int next;
};
EDGE edge[maxn];
struct node
{
int u, d;
node(int u, int d)
:u(u), d(d) {}
bool operator < (const node& p)const
{
return d > p.d;
}
};
void ini()
{
cnt = 0;
memset(vis, 0, sizeof(vis));
memset(dis, INF, sizeof(dis));
for (int i = 0; i <= n; i++)
head[i] = -1;
/*for (int i = 0; i <= n; i++)
{
head[i] = -1;
vis[i] = 0;
dis[i] = INF;
}*/
}
void addedge(int u, int v, int w)
{
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
ll dijkstra()
{
priority_queue<node> q;
q.push(node(1, 0));//node(int u, int d)
//vis[1] = 1;
dis[1] = 0;
while (!q.empty())
{
node now = q.top(); q.pop();
int u = now.u;//当前最短边的一个端点u
//if (vis[u])continue;
if (!vis[u])
{
vis[u] = 1;
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;//新添加一个点,该点为最短边的除了u的另外一个端点v
int w = edge[i].w;
if (!vis[v] && dis[v] > dis[u] + w)//更新
{
dis[v] = dis[u] + w;
q.push(node(v, dis[v]));
}
}
}
}
ll ans = 0;
for (int i = 1; i <= n; i++)
ans += dis[i];
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> T;
while (T--)
{
cin >> n >> m;
ini();//输入n,m后,再初始化
for (int i = 0; i < m; i++)
{
//cin >> a[i][0] >> a[i][1] >> a[i][2];
scanf("%d%d%d", &a[i][0], &a[i][1], &a[i][2]);
addedge(a[i][0], a[i][1], a[i][2]);
}
ll ans = dijkstra();
ini();
for (int i = 0; i < m; i++)//将边反向
addedge(a[i][1], a[i][0], a[i][2]);
ans += dijkstra();
cout << ans << endl;
}
return 0;
}