J - Invitation Cards POJ - 1511
题意: 共有 n 个站点,n 个志愿者从1 出发,分别到达不同的站点,晚上全部回到 1 ,求他们总的最小花费是多少?
思路: 首先想到从 1 出发跑一遍 DJ, 然后再以每一个点为起点出发跑 n-1 遍 DJ ,求出所有 dis[1] + dis2[i] 即可,但是看了一下复杂度, n <= 1e6, 炸了
优化一下,从 1 出发跑一边 DJ 后,反向建图,然后再从 1 出发跑一遍,答案就有了
复杂度:O(2*nlogn)=4e7
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
typedef pair<ll,int> PII;
const int maxn = 1e6+10;
int n, m;
int u[maxn], v[maxn], w[maxn];
inline int read() {
char c = getchar(); int f = 1, x = 0;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return f * x;
}
int head[maxn], cnt;
bool vis[maxn];
struct node{
int to, next, w;
}e[maxn];
void add(int u, int v, int w) {
e[++cnt].next = head[u];
e[cnt].to = v;
e[cnt].w = w;
head[u] = cnt;
}
ll dis[maxn];
void init() {
memset(vis, 0, sizeof(vis));
memset(head, 0, sizeof(head));
cnt = 0;
memset(dis, 0x3f3f3f3f3f3f3f3f, sizeof(dis));
memset(e, 0, sizeof(e));
}
ll dijkstra() { // 每次取出与连通块相邻的所有边中最小的一条加入连通图,直至所有边都在连通块内
dis[1] = 0;
priority_queue<PII, vector<PII>, greater<PII> > heap;
heap.push({0, 1});
while(heap.size()) {
PII now = heap.top(); heap.pop();
ll dist = now.first; int u = now.second;
if(vis[u]) continue;
vis[u] = 1;
for(int i = head[u]; i; i = e[i].next) {
int to = e[i].to;
if(dis[to] > dist + e[i].w) {
dis[to] = dist +e[i].w; // 后面进入的点可以更新与其相邻的,先进入的点
heap.push({dis[to], to});
}
}
}
// 统计答案
ll sum = 0;
for(int i = 1; i <= n; i++) sum += dis[i];
return sum;
}
int main() {
// freopen("test.in", "r", stdin);
int T = read();
while(T--) {
ll ans = 0;
init();
n = read(); m = read();
for(int i = 1; i <= m; i++) {
u[i] = read(), v[i] = read(), w[i] = read();
add(u[i], v[i], w[i]);
}
ans += dijkstra();
init();
for(int i = 1; i <= m; i++) add(v[i], u[i], w[i]);
ans += dijkstra();
printf("%lld\n", ans);
}
return 0;
}