最小生成树练习2(Kruskal)

两个BUG鸣翠柳,一行代码上西天。。。031FA85F

hdu4786 Fibonacci Tree(生成树)问能否用白边和黑边构成一棵生成树,并且白边数量是斐波那契数。

题解:分别优先加入白边和黑边,求出生成树能包含白边的最大值和最小值,其间有值为斐波那契数即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int M=1e5+1;
 6 const int N=1e5+1;
 7 struct edge{
 8     int u,v,w;
 9 }e[M];
10 int f[N];
11 int fi[20];
12 int n,m,ans;
13 int cmp(edge a,edge b){
14     return a.w<b.w;
15 }
16 void init(){
17     for(int i=1;i<=n;++i) f[i]=i;
18 }
19 int fin(int x){
20     if(x!=f[x])f[x]=fin(f[x]);
21     return f[x];
22 }
23 void Kruskal(){
24     int u,v,i,cnt=0,mi=0,ma=0,flag=0;
25     init();
26     for(i=0;i<m;++i){
27         u=e[i].u;
28         v=e[i].v;
29         if((u=fin(u))!=(v=fin(v))){
30             f[u]=v;
31             if(e[i].w) mi++;
32             if(++cnt==n-1){flag=1;break;}
33         }
34     }
35     if(!flag){printf("No
");return;}
36     init();
37     for(i=m-1;i>=0;--i){
38         u=e[i].u;
39         v=e[i].v;
40         if((u=fin(u))!=(v=fin(v))){
41             f[u]=v;
42             if(e[i].w) ma++;
43             if(++cnt==n-1)break;
44         }
45     }
46     for(i=1;i<20;++i)
47         if(mi<=fi[i]&&fi[i]<=ma){
48             printf("Yes
");return;
49         }
50     printf("No
");
51 }
52 int main(){
53     int t,i,a,b,c,k=1;
54     fi[1]=1;fi[2]=2;
55     for(i=3;i<20;++i)
56         fi[i]=fi[i-1]+fi[i-2];
57     //printf(".%d.",fi[19]);
58     scanf("%d",&t);
59     while(t--){
60         scanf("%d%d",&n,&m);
61         for(i=0;i<m;++i){
62             scanf("%d%d%d",&a,&b,&c);
63             e[i]={a,b,c};
64         }
65         sort(e,e+m,cmp);
66         printf("Case #%d: ",k++);
67         Kruskal();
68     }
69     return 0;
70 }
View Code

hdu5253 连接的管道(最小生成树)一开始我因为没建好图纠结了ToT~

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 using namespace std;
 5 const int N=1000;
 6 struct edge{
 7     int u,v,w;
 8 }e[N*N*2];
 9 int f[N*N];
10 int g[N][N];
11 int ei,n,m,ans;
12 int cmp(edge a,edge b){
13     return a.w<b.w;
14 }
15 int fin(int x){
16     if(x!=f[x])f[x]=fin(f[x]);
17     return f[x];
18 }
19 void Kruskal(){
20     int u,v,i,cnt=0;
21     for(ans=i=0;i<ei;++i){
22         u=e[i].u;
23         v=e[i].v;
24         if((u=fin(u))!=(v=fin(v))){
25             f[u]=v;
26             ans+=e[i].w;
27             if(++cnt==n*m-1)break;
28         }
29     }
30 }
31 int main(){
32     int t,i,j,h,k=1;
33     scanf("%d",&t);
34     while(t--){
35         ei=0;
36         scanf("%d%d",&n,&m);
37         for(i=0;i<n;++i){
38             for(j=0;j<m;++j){
39                 scanf("%d",&g[i][j]);
40                 f[i*m+j]=i*m+j;
41                 if(i>0){
42                     e[ei].u=i*m+j; e[ei].v=(i-1)*m+j;
43                     e[ei++].w=abs(g[i][j]-g[i-1][j]);
44                 }
45                 if(j>0){
46                     e[ei].u=i*m+j; e[ei].v=i*m+j-1;
47                     e[ei++].w=abs(g[i][j]-g[i][j-1]);
48                 }
49             }
50         }
51         sort(e,e+ei,cmp);
52         Kruskal();
53         printf("Case #%d:
%d
",k++,ans);
54     }
55     return 0;
56 }
View Code

hdu1598 find the most comfortable road(最小生成树,枚举)第一眼看过去差点想最短路[吓],,这是最小差不是最短路哦。用Kruskal要对边排序,贪心正好哩。枚举最小道路建树,起点和终点连上了就记录最大边与最小边之差,最后选所有情况的最小值就行啦。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 using namespace std;
 5 const int inf=0x3f3f3f3f;
 6 const int M=1000;
 7 struct edge{
 8     int u,v,w;
 9 }e[M];
10 int f[201];
11 int n,m,ans,st,ed;
12 int cmp(edge a,edge b){
13     return a.w<b.w;
14 }
15 void init(){
16     for(int i=1;i<=n;++i)
17         f[i]=i;
18 }
19 int fin(int x){
20     if(x!=f[x])f[x]=fin(f[x]);
21     return f[x];
22 }
23 void Kruskal(){
24     int u,v,i,j;
25     ans=inf;
26     for(i=0;i<m;++i){//枚举
27         init();
28         for(j=i;j<m&&e[j].w-e[i].w<ans;++j){
29             u=e[j].u;
30             v=e[j].v;
31             if((u=fin(u))!=(v=fin(v))){
32                 f[u]=v;
33             }
34             if(fin(st)==fin(ed)){
35                 ans=min(ans,e[j].w-e[i].w);
36                 break;
37             }
38         }
39     }
40 }
41 int main(){
42     int i,j,q;
43     while(scanf("%d%d",&n,&m)==2){
44         for(i=0;i<m;++i)
45             scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
46         sort(e,e+m,cmp);
47         scanf("%d",&q);
48         while(q--){
49             scanf("%d%d",&st,&ed);
50             Kruskal();
51             printf("%d
",(ans==inf)?-1:ans);
52         }
53     }
54     return 0;
55 }
View Code

poj3522 Slim Span(最小生成树,枚举)求最大边与最小边之差最小的生成树。和上面那题挺像的,相比之下,这题就是完整的最小生成树了。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 using namespace std;
 5 const int inf=0x3f3f3f3f;
 6 const int N=101;
 7 struct edge{
 8     int u,v,w;
 9 }e[5000];
10 int f[N];
11 int n,m,ans,st,ed;
12 int cmp(edge a,edge b){
13     return a.w<b.w;
14 }
15 void init(){
16     for(int i=1;i<=n;++i)
17         f[i]=i;
18 }
19 int fin(int x){
20     if(x!=f[x])f[x]=fin(f[x]);
21     return f[x];
22 }
23 void Kruskal(){
24     int u,v,i,j,cnt;
25     ans=inf;
26     for(i=0;i<m;++i){
27         init(); cnt=0;
28         for(j=i;j<m&&e[j].w-e[i].w<ans;++j){
29             u=e[j].u;
30             v=e[j].v;
31             if((u=fin(u))!=(v=fin(v))){
32                 f[u]=v;
33                 if(++cnt==n-1){
34                     ans=min(ans,e[j].w-e[i].w);
35                     break;
36                 }
37             }
38         }
39     }
40 }
41 int main(){
42     int i,j,q;
43     while(scanf("%d%d",&n,&m),n||m){
44         for(i=0;i<m;++i)
45             scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
46         sort(e,e+m,cmp);
47         Kruskal();
48         printf("%d
",(ans==inf)?-1:ans);
49     }
50     return 0;
51 }
View Code

poj2784 Buy or Build(最小生成树,二进制枚举)英语渣在艰难地读题orz。已知n个城市的坐标,q个连通块各自的费用,新建一条边的费用为两点距离的平方。求最小生成树。学了一下二进制枚举法。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<vector>
 4 using namespace std;
 5 const int N=1001;
 6 struct edge{
 7     int u,v,w;
 8 }e[500000];
 9 struct node{
10     int x,y;
11 }V[N];
12 int f[N];
13 int a[10];
14 int n,m,q;
15 vector<int>g[10];
16 int cmp(edge a,edge b){
17     return a.w<b.w;
18 }
19 int dist(int i,int j){
20     return (V[i].x-V[j].x)*(V[i].x-V[j].x)+(V[i].y-V[j].y)*(V[i].y-V[j].y);
21 }
22 void init(){
23     for(int i=1;i<=n;++i)
24         f[i]=i;
25 }
26 int fin(int x){
27     if(x!=f[x])f[x]=fin(f[x]);
28     return f[x];
29 }
30 void uni(int x,int y){
31     if((x=fin(x))==(y=fin(y)))return;
32     f[x]=y;
33 }
34 int Kruskal(){
35     int u,v,i,j,cnt=0,ans=0;
36     for(i=0;i<m;++i){
37         u=e[i].u;
38         v=e[i].v;
39         if((u=fin(u))!=(v=fin(v))){
40             f[u]=v;
41             ans+=e[i].w;
42             if(++cnt==n-1)break;
43         }
44     }
45     //printf("%d..
",ans);
46     return ans;
47 }
48 void solve(){
49     int i,j,k,cost,ans;
50     init();
51     ans=Kruskal();
52     for(i=0;i<(1<<q);++i){//枚举方案
53         cost=0;
54         init();
55         for(j=0;j<q;++j){
56             if(!((i>>j)&1))continue;//二进制枚举
57             cost+=a[j];
58             //printf("COST:%d..",cost);
59             for(k=1;k<g[j].size();++k)
60                 uni(g[j][k],g[j][0]);
61         }
62         ans=min(ans,cost+Kruskal());
63     }
64     printf("%d
",ans);
65 }
66 int main(){
67     int i,j,num,x;
68     while(scanf("%d%d",&n,&q)==2){
69         for(i=0;i<q;++i){
70             g[i].clear();
71             scanf("%d%d",&num,&a[i]);
72             for(j=0;j<num;++j){
73                 scanf("%d",&x);
74                 g[i].push_back(x);
75             }
76         }
77         for(i=1;i<=n;++i) scanf("%d%d",&V[i].x,&V[i].y);
78         m=0;
79         for(i=1;i<n;++i){
80             for(j=i+1;j<=n;++j){
81                 e[m].u=i; e[m].v=j;
82                 e[m++].w=dist(i,j);
83             }
84         }
85         sort(e,e+m,cmp);
86         solve();
87     }
88     return 0;
89 }
View Code
原文地址:https://www.cnblogs.com/GraceSkyer/p/5778231.html