1640 天气晴朗的魔法
http://www.51nod.com/Challenge/Problem.html#!#problemId=1640
题目来源: 原创
基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题
这样阴沉的天气持续下去,我们不免担心起他的健康。
51nod魔法学校近日开展了主题为“天气晴朗”的魔法交流活动。
N名魔法师按阵法站好,之后选取N - 1条魔法链将所有魔法师的魔力连接起来,形成一个魔法阵。
魔法链是做法成功与否的关键。每一条魔法链都有一个魔力值V,魔法最终的效果取决于阵中所有魔法链的魔力值的和。
由于逆天改命的魔法过于暴力,所以我们要求阵中的魔法链的魔力值最大值尽可能的小,与此同时,魔力值之和要尽可能的大。
现在给定魔法师人数N,魔法链数目M。求此魔法阵的最大效果。
Input
两个正整数N,M。(1 <= N <= 10^5, N <= M <= 2 * 10^5)
接下来M行,每一行有三个整数A, B, V。(1 <= A, B <= N, INT_MIN <= V <= INT_MAX)
保证输入数据合法。
Output
输出一个正整数R,表示符合条件的魔法阵的魔力值之和。
Input示例
4 6
1 2 3
1 3 1
1 4 7
2 3 4
2 4 5
3 4 6
Output示例
12
分析: 这是一个最小生成树的题,通过Kurstal算法 先求出 最小生成树的 最大的权值,
然后 再把边 按权值从大到小排序,求出 最大权值和
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct Node{
int u ,v, w;
} eg[200005];
int father[200010];
int cmp1(const Node a, const Node b){ //按权值从小到大排序
return a.w < b.w;
}
int cmp2(const Node a, const Node b){ //按权值从大到小排序
return a.w > b.w;
}
int find( int x ){
return father[x] == x ? x : father[x] = find( father[x] );
}
void merge( int x ,int y ){
int fx = find( x );
int fy = find( y );
if( fx != fy ){
father[fx] = fy;
}
}
void init( int n ){
for( int i=0;i<=n;i++)
father[i] = i;
}
int main(void){
int a,b,n,M;
scanf("%d%d",&n,&M);
for( int i=0;i <M ; i++ )
scanf("%d%d%d",&eg[i].u,&eg[i].v,&eg[i].w);
// 从小到大排序
sort(eg,eg+M,cmp1);
// 跑最小生成树算法 ,
// 求出能生成最小生成树的情况下,求其中 单条魔法链的 最大权值
init(n); // 先初始化,父亲节点
int maxx = -1;
for( int i=0;i<M;i++){ //找最小生成树
a = eg[i].u;
b = eg[i].v;
if( find(a) != find(b) ){
if( eg[i].w > maxx ){
maxx = eg[i].w;
}
merge(a,b);
}
}
// 在能生成最小生成树的条件下, 求最大权值之和
long long int ans = 0;
init(n);
sort(eg,eg+M,cmp2); // 按权值从大到小排序
for( int i=0;i<M;i++){ //找最小生成树
a = eg[i].u;
b = eg[i].v;
if( find(a) != find(b) ){
if( eg[i].w <= maxx ){
merge(a,b);
ans+=eg[i].w;
}
}
}
printf("%lld\n",ans);
return 0;
}