描述
题解
每次做题都是读一遍题没读懂,然后就去看翻译……真心塞。
这道题题意是求从1号结点到所有结点的最短路之和,然后再返回1号结点的最短路之和的和。
比较直观的使用SPFA搞搞,但是这是单源最短路,求第一个过程很容易,可是第二个过程如果死板硬套,那么需要进行n-1
次SPFA,加起来也就是n
次SPFA,这样必然会超时的,所以我们需要反向建图,因为从其他结点到1号结点的最短路如果反向一下,不就是从1号结点到其他结点的最短路吗?所以整个题需要正向建图SPFA一发,求得第一部分,然后反向建图SPFA一发,求得第二部分,求两部分之和即可。
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int MAXP = 1e6 + 10;
const int INF = 0x3f3f3f3f;
struct Edge
{
int v;
int cost;
Edge(int _v = 0, int _cost = 0) : v(_v), cost(_cost) {}
};
vector<Edge> E[MAXP];
void init()
{
for (int i = 0; i < MAXP; i++)
{
E[i].clear();
}
}
void addEdge(int u, int v, int w)
{
E[u].push_back(Edge(v, w));
}
bool vis[MAXP];
int cnt[MAXP];
int dist[MAXP];
bool SPFA(int start, int n)
{
memset(vis, false, sizeof(vis));
memset(dist, 0x3f, sizeof(dist));
memset(cnt, 0, sizeof(cnt));
vis[start] = true;
dist[start] = 0;
queue<int> que;
while (!que.empty())
{
que.pop();
}
que.push(start);
cnt[start] = 1;
while (!que.empty())
{
int u = que.front();
que.pop();
vis[u] = false;
for (int i = 0; i < E[u].size(); i++)
{
int v = E[u][i].v;
if (dist[v] > dist[u] + E[u][i].cost)
{
dist[v] = dist[u] + E[u][i].cost;
if (!vis[v])
{
vis[v] = true;
que.push(v);
if (++cnt[v] > n)
{
return false;
}
}
}
}
}
return true;
}
int st[MAXP];
int ed[MAXP];
int val[MAXP];
int main(int argc, const char * argv[])
{
int N;
cin >> N;
int P, Q, sum;
while (N--)
{
sum = 0;
init();
scanf("%d%d", &P, &Q);
for (int i = 0; i < Q; i++)
{
scanf("%d%d%d", &st[i], &ed[i], &val[i]);
addEdge(st[i], ed[i], val[i]);
}
SPFA(1, P);
for (int i = 1; i <= P; i++)
{
sum += dist[i];
}
init();
for (int i = 0; i < Q; i++)
{
addEdge(ed[i], st[i], val[i]);
}
SPFA(1, P);
for (int i = 1; i <= P; i++)
{
sum += dist[i];
}
cout << sum << '\n';
}
return 0;
}