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
题面明确,构成一个连接连接所有点的树.其中最大的边尽可能小,在这个前提下,其他边尽量大.
1: 最大的边尽可能小,那么可以用kurskal算法或者prim算法算法他的最小生成树,记录最大的那条边。
2: 然后就知道,就算只选取小于这条边的边,也至少能构成1棵树(最小生成树),根据题目要求,优先选择大的边(但要小于1中记录的最大值)
3: 很明显这里用kurskal更加的方便,因为优先选择大的边,在一开始构成最小生成树时已经排序好,记录最大边的位置,从尾到头重新遍历即可。
4:注意如果有边和最大边一样长,也要记录,还有就是sort语句的自定义排序语句,情况为'=='时不能返回1,今天还特意问人查资料,具体原因自行百度补一波更清楚。
并查集不会的话,可以看我上一篇博客有我点一点理解。
我推荐一个视频:http://www.bilibili.com/video/av8373130/
这是某大佬的教学,讲的很好,吃个饭一边看5分钟,吃完就会并查集了。
然后 献上代码:
#include
#include
#include
#include
#include
using namespace std;
long long int ans=0;
int fu[100005],i,j,n,m,gen1,gen2,maxbian=0,maxbnum;
struct bi
{
int from,to,leng;
}bian[200005];
int cmp1(bi a,bi b) //小的边在前面
{
return a.lenga.leng;
}
int FindGen(int x) //路径压缩 查找
{
int a,b;
a=x;//保存初始值
while(fu[x]!=x)//找到根节点,而不是父节点
x=fu[x]; //得到根点x
//下面开始路径压缩
while(fu[a]!=x)//不是根的直接子点
{
b=fu[a];//保存父点,方便更改
fu[a]=x;
a=b;
}
return x;
}
int main()
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) //父节点数组初始化
fu[i]=i;
for(i=0;imaxbian)
{
maxbian=bian[i].leng;
maxbnum=i;
}
}
if(bian[i].leng==maxbian&&maxbnum!=i)//可能最大边不止一条
maxbnum=i;
}
for(i=1;i<=n;i++) //父节点数组初始化
fu[i]=i;
for(i=maxbnum;i>=0;i--)
{
gen1=FindGen(bian[i].from); //分别两个点的根点
gen2=FindGen(bian[i].to);
if(gen1!=gen2) //根不同
{
ans+=bian[i].leng;
fu[gen1]=gen2; //并合
}
}
printf("%lld",ans);
return 0;
}