题目链接:【http://poj.org/problem?id=3228】
题意:给出n个村庄,每个村庄有金矿和仓库,然后给出m条边连接着这个村子。问题是把所有的金矿都移动到仓库里所要经过的路径的最大值的最小值。
题解:贪心,把边排序,然后从小到大加边,如果加到某一条边之后,金矿都可以移动到仓库了,那么这条边就是结果。首先明白,如果一些边连接的一些村庄的仓库的总容量大于总金矿数,那么这些村庄的金矿就可以全部移动到仓库里了。如果在从小到大加边的时候形成了环,那么这条边可以不要(加进去也不会影响结果),然后用并查集维护就可以了,注意:在用并查集维护的时候,记得把仓库和金矿都移动到根节点,这样便于判断是否已经满足了情况了。
//#include<bits/stdc++.h> #include<cstdio> #include<cstring> #include<algorithm> typedef long long LL; using namespace std; const int maxn = 250; struct node { int st, ed, dis; bool operator < (const node T) const { return dis < T.dis; } } E[maxn * maxn]; int g[maxn], h[maxn], N, M; int f[maxn]; int Find(int u) { if(u == f[u]) return f[u]; else return f[u] = Find(f[u]); } void adde(int u, int v) { f[u] = v; h[v] += h[u]; h[u] = 0; g[v] += g[u]; g[u] = 0; } bool check() { for(int i = 1; i <= N; i++) { int u = Find(i); if(h[u] < g[u]) return false; } return true; } int main () { while(~scanf("%d", &N), N) { for(int i = 1; i <= N; i++) f[i] = i; int sumg = 0, sumh = 0; for(int i = 1; i <= N; i++) { scanf("%d", &g[i]); sumg += g[i]; } for(int i = 1; i <= N; i++) { scanf("%d", &h[i]); sumh += h[i]; } if(sumh < sumg) { printf("No Solution "); continue; } scanf("%d", &M); for(int i = 1; i <= M; i++) scanf("%d%d%d", &E[i].st, &E[i].ed, &E[i].dis); sort(E + 1, E + 1 + M); int ans = 0; if(check()) { printf("%d ", ans); continue; } for(int i = 1; i <= M; i++) { int u = Find(E[i].st); int v = Find(E[i].ed); if(u == v) continue; adde(u, v); ans = E[i].dis; if(check()) break; } if(check()) printf("%d ", ans); else printf("No Solution "); } return 0; }