http://acm.whu.edu.cn/land/problem/detail?problem_id=1542
题意说,有n个点和m条边,有的点之间是距离为0,距离为零的点可以构成一个联通块,还有的点之间距离大于0。联通块的个数不会超过200,问你任意两个点之间的最短距离。
解题思路:
首先既然是不超过200个联通块,要你求最短距离,直接可以用floyed撸O(n^3);然后只要想到用并查集做缩点,并且记录每个点在哪个联通块里就可以了。
题目代码:
#include <iostream> #include <cstdio> #include <cstdlib> #define FOR(a,b,c) for (int a=b,_c=c;a<=_c;a++) #define REP(i,a) for(int i=0,_a=(a); i<_a; ++i) #define oo 1000000007 using namespace std; typedef long long ll; typedef pair<int, int> pii; const int maxn = 100100; struct Node { int u, v, val; }; Node edge[maxn]; int p[maxn]; int dis[222][222]; int Map[maxn]; int cnt; int find(int x) { return x != p[x] ? p[x]=find(p[x]) : x; } int main() { // freopen("data.in", "r", stdin); int m, n, q, fu, fv, f,ans; while(scanf("%d", &n) != EOF && n != 0) { scanf("%d", &m); FOR(i, 1, n) p[i] = i; REP(i, m) { scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].val); if(edge[i].val == 0) { fu = find(edge[i].u); fv = find(edge[i].v); if(fu != fv) p[fv] = fu; } } cnt = 0; FOR(i, 1, n) { f = find(i); if(f == i) { Map[i] = ++cnt; } } FOR(i, 1, n) { f = find(i); if(f != i) { Map[i] = Map[f]; } } FOR(i, 1, cnt){ FOR(j, 1, cnt) { dis[i][j] = oo; } dis[i][i] = 0; } REP(i, m) { if(edge[i].val) { fu = find(edge[i].u); fv = find(edge[i].v); fu = Map[fu]; fv = Map[fv]; dis[fu][fv] = min(dis[fu][fv], edge[i].val); dis[fv][fu] = min(dis[fv][fu], edge[i].val); } } FOR(k, 1, cnt) FOR(i, 1, cnt) FOR(j, 1, cnt) dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); scanf("%d", &q); while(q--) { scanf("%d%d", &fu, &fv); fu = find(fu); fv = find(fv); if(fu == fv) { ans = 0; }else { fu = Map[fu]; fv = Map[fv]; ans = dis[fu][fv]; if(ans == oo) ans = -1; } printf("%d\n", ans); } } return 0; }