Bad Cowtractors
Time Limit: 1000MS Memory Limit: 65536K
Description
Bessie has been hired to build a cheap internet network among Farmer John’s N (2 <= N <= 1,000) barns that are conveniently numbered 1..N. FJ has already done some surveying, and found M (1 <= M <= 20,000) possible connection routes between pairs of barns. Each possible connection route has an associated cost C (1 <= C <= 100,000). Farmer John wants to spend the least amount on connecting the network; he doesn’t even want to pay Bessie.
Realizing Farmer John will not pay her, Bessie decides to do the worst job possible. She must decide on a set of connections to install so that (i) the total cost of these connections is as large as possible, (ii) all the barns are connected together (so that it is possible to reach any barn from any other barn via a path of installed connections), and (iii) so that there are no cycles among the connections (which Farmer John would easily be able to detect). Conditions (ii) and (iii) ensure that the final set of connections will look like a “tree”.
Input
* Line 1: Two space-separated integers: N and M
* Lines 2..M+1: Each line contains three space-separated integers A, B, and C that describe a connection route between barns A and B of cost C.
Output
* Line 1: A single integer, containing the price of the most expensive tree connecting all the barns. If it is not possible to connect all the barns, output -1.
Sample Input
5 8
1 2 3
1 3 7
2 3 10
2 4 4
2 5 8
3 4 6
3 5 2
4 5 17
Sample Output
42
Hint
OUTPUT DETAILS:
The most expensive tree has cost 17 + 8 + 10 + 7 = 42. It uses the following connections: 4 to 5, 2 to 5, 2 to 3, and 1 to 3.
Source
http://poj.org/problem?id=2377
这个题是要建立一个最大生成树,但是可以用最小生成树的模板。即把数据取相反数输入,然后求出一个最小值,再求相反数即结果。
注:此题可能会对同一路径重复赋不同的权值,这时要判断选出最优的权值。
样例图示:
AC的代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 1010 //最多顶点数
#define MAX 0x3f3f3f3f //模拟无穷大
int map[N][N]; //存储各顶点间的权值
int flag[N]; //标记是否已纳入树
int dis[N]; //已纳入点和其余各点的最小权值
int prim(int n) //普利姆函数
{
int i, j;
int now; //记录新纳入的点
int min; //记录新纳入的点到其余已纳入的点的最小权值
int sum = 0; //最小生成树权值和
memset(dis, MAX, sizeof(dis)); //初始化dis数组为无穷大
memset(flag, 0, sizeof(flag)); //初始化flag数组,0表示此点未被纳入
/*这里随机选取了1号点为初始时被纳入的顶点*/
for(i = 1; i <= n; i++)
dis[i] = map[1][i]; //与1号点与其他点的权值存入dis数组
dis[1] = 0; //一号点到其本身的权值为0
flag[1] = 1; //标记为已纳入
for(i = 1; i < n; i++){ //除去初始时随机纳入的点还有n-1个点应被纳入
now = min = MAX; //初始为无穷大表示两点间无通路
for(j = 1; j <= n; j++){ //遍历
if(flag[j] == 0){
if(dis[j] < min){ //寻找与已纳入各点权值最小的点
now = j;
min = dis[j];
}
}
}
if(now == MAX) //若now等于max,则证明所有与初始时纳入的点连通的点已全被纳入
break;
sum += min; //将找到的点纳入并标记
flag[now] = 1;
for(j = 1; j <= n; j++){
/*
遍历比较之前纳入点到未纳入点的权值的最小值
与刚纳入点到未纳入点的权值
并用dis[j]存储新的最小值
*/
if(flag[j] == 0)
if(dis[j] > map[now][j])
dis[j] = map[now][j];
}
}
if(i == n) //若i等于n则证明已经建立最小生成树
return sum;
else
return -1;
}
int main(void)
{
int i, j, k;
int n; //顶点数
int m;
while(scanf("%d%d", &n, &m) != EOF){
memset(map, MAX, sizeof(map));
while(m--){
scanf("%d%d%d", &i, &j, &k);
if(-k < map[i][j]) //对权值重复输入时要判断
map[i][j] = map[j][i] = -k;
}
if((k = prim(n)) != -1)
printf("%d\n", -k);
else
printf("-1\n");
}
return 0;
}