题意:
4 //表示有n 个村庄
3 2 0 0 //每个村庄金库数;
0 0 3 3 //每个村庄仓库数
6 //村与村间路的条数。
1 2 4 //x 到 y 间的距离 len;
1 3 10
1 4 12
2 3 6
2 4 8
3 4 5
求将所有的金库运到仓库所走的最短路径中最长的两个村村间的距离。
做法:
现将所有的边排序,后用并查集从小边开始合并。当金库总数等于零时停止。即为所求的最大边。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
using namespace std;
const int M = 205;
int sum[M];
int sumgold, sumstorage;
int n,m, cnt;
struct node {
int x, y;
int len;
}edge[M*M];
int p[M], ans;
void init(){
ans = -1;
sumgold = 0;
sumstorage = 0;
for(int i = 1; i <= n; i++){
p[i] = i;
sum[i] = 0;
}
}
void input(){
int a;
for(int i = 1; i <= n; i++){
scanf("%d", &a);
sum[i] -= a;
}
for(int i = 1; i <= n; i++){
scanf("%d", &a);
sum[i]+= a;
sumstorage += sum[i];
if(sum[i] < 0)
sumgold += abs(sum[i]);
}
//printf("%d %d \n", sumgold , sumstorage);
scanf("%d", &m);
for(int i = 0; i < m; i++){
scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].len);
}
}
bool cmp(node p1, node p2){
return p1.len < p2.len;
}
int Find(int x){
return x == p[x] ? x : p[x] = Find(p[x]);
}
void check(int x, int y){ //很好的方法;
if(sum[x]*sum[y] < 0){ // 很好的方法,判断两个数异号;
if(sum[x] + sum[y] >0){ //用求和的方式,判断正数大还是负数大;
sumgold += min(sum[x], sum[y]);
}else {
sumgold -= max(sum[x], sum[y]);
}
}
sum[y] = sum[x] + sum[y];
sum[x] = 0;
}
void work(){
if(sumstorage < 0){
// printf("___________________\n");
printf("No Solution\n");
return ;
}
sort(edge, edge+m, cmp);
// for(int i = 0; i < m; i++){
//
// printf("%d %d %d %d \n", i, edge[i].x, edge[i].y, edge[i].len);
// }
for(int i = 0; i < m; i++){
int a = Find(edge[i].x);
int b = Find(edge[i].y);
// printf("%d %d\n", edge[i].x, edge[i].y);
if(a != b){
p[a] = b;
check(a, b);
// printf("i = %d %d %d, %d %d\n", i, gold[b], storage[b], sumgold, sumstorage);
if(sumgold <= 0){
ans = edge[i].len;
break;
}
}
}
if(ans == -1)
printf("No Solution\n");
else
printf("%d\n", ans);
}
int main()
{
while(scanf("%d", &n), n){
init();
input();
work();
}
return 0;
}