【克鲁斯卡尔蒜法-最小生成树算法】-zzuli-2271 -Problem -E-魔法交流活动

问题 E: 魔法交流活动

题目描述

魔法学校近日开展了主题为“天气晴朗”的魔法交流活动。
N名魔法师按阵法站好,之后选取N - 1条魔法链将所有魔法师的魔力连接起来,形成一个魔法阵。
魔法链是做法成功与否的关键。每一条魔法链都有一个魔力值V,魔法最终的效果取决于阵中所有魔法链的魔力值的和。
由于逆天改命的魔法过于暴力,所以我们要求阵中的魔法链的魔力值最大值尽可能的小,与此同时,魔力值之和要尽可能的大。
现在给定魔法师人数N,魔法链数目M。求此魔法阵的最大效果。

输入

两个正整数N,M。(1 <= N <= 10^5, N <= M <= 2 * 10^5) 
接下来M行,每一行有三个整数A, B, V。(1 <= A, B <= N, INT_MIN <= V <= INT_MAX) 
保证输入数据合法。

输出

输出一个正整数R,表示符合条件的魔法阵的魔力值之和。

样例输入

4 6
1 2 3
1 3 1
1 4 7
2 3 4
2 4 5
3 4 6

样例输出

12
-

大致题意分析:

   有n个点,选取n-1条边把他们全部连起来形成一棵树,每条边都有一个权值;要求1:所有的边的权值的最大值最小,然后还又要求2:这棵树中的所有的边权值的和最大。

  思路:这个题目是对边来进行筛选的,需要用克鲁斯卡尔蒜法。这个蒜法是对边来进行操作的,按照边来逐渐形成整棵最小生成树。

                 具体需要跑两边,第一遍从小到大对边进行一次筛选,筛选出的边的集合可以构成一颗树即可;这是最后一条新加进来的边就是最大的权值maxmin(要求1达成)。

    第二遍,从大到小,具体从等于maxmin的边开始跑一遍,直到筛选出的边的集合可以构成一颗树即可,进行筛选、求和,即为最终结果。


代码:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <queue>
 6 #include <stack>
 7 #include <vector>
 8 #include<math.h>
 9 #include <string.h>
10 #include<set>
11 using namespace std;
12 #define inf 0x7fffffff
13 #define maxn 10000000
14 const double pi=acos(-1.0);
15 #define ll long long
16 #define N 100008
17 //vector<int>G[N];
18 int n,m;
19 struct Edge{
20     int a,b;//两个顶点的编号
21     ll dis;
22     Edge(int a=0,int b=0,ll dis=0):a(a),b(b),dis(dis){}
23 }edge[N*2];
24 int root[N];
25 ll fans;
26 
27 void init(int n){
28 
29     for(int i=1;i<=n;i++)
30         root[i]=i;
31 }
32 
33 
34 int findroot(int a){//返回点a的根节点
35     if(root[a]==a)
36         return a;
37     return root[a]=findroot(root[a]);
38 }
39 int unite(int a,int b){//将a和b节点用并查集的思路连接到一起
40     if(a==b)return 0;//在联通块内部加上的边
41     else{
42         root[a]=b;return 1;
43     }
44 }
45 bool cmp(Edge x,Edge y){
46     return x.dis<y.dis;
47 }
48 int fact1(int n){//计算出maxlmin-len
49     int cnt=0;
50     ll ans=(ll)inf*(-1);
51     int i=1;
52     while(cnt<n-1){
53         if(unite(findroot(edge[i].a),findroot(edge[i].b))==1 ){
54             cnt++;
55             ans=max(ans,edge[i].dis);
56         }
57         i++;
58     }
59     return ans;
60 }
61 ll fact2(int n,int maxlen){//
62     for(int i=1;i<=n;i++)
63         root[i]=i;
64     int cnt=0;
65     ll ans=0;
66     int i=m;
67     while(i>0&&cnt<n-1){
68         if(edge[i].dis<=(ll)maxlen && unite(findroot(edge[i].a),findroot(edge[i].b))==1 ){
69             cnt++;
70             ans+=edge[i].dis;
71         }
72         i--;
73     }
74     return ans;
75 }
76 int main(){
77     while(scanf("%d%d",&n,&m)!=EOF){
78         init(n);
79         int x,y;ll v;
80         for(int i=1;i<=m;i++){
81             scanf("%d%d%lld",&x,&y,&v);
82             edge[i]=Edge(x,y,v);
83           //  G[x].push_back(y);G[x].push_back(v);
84           //  G[y].push_back(x);G[y].push_back(v);
85         }
86         sort(edge+1,edge+1+m,cmp);//按边权值升序排列
87         int maxlen=fact1(n);//找到合法的最大长度
88 
89     // printf("maxmin=%d\n",maxlen);
90       //  vis[1]=true;
91 
92         printf("%lld\n",fact2(n,maxlen));
93     }
94 
95     return 0;
96 }
View Code(据说有注释)

猜你喜欢

转载自www.cnblogs.com/zhazhaacmer/p/9034779.html