• 最小生成树练习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
  • 相关阅读:
    成为JAVA(高级)工程师
    JVM的内存区域划分以及垃圾回收机制
    XML
    String.valueOf
    JAVA书籍(2)
    JAVA书籍(1)
    深入JAVA线程池
    FileWriter与BufferedWriter
    获取下拉框的文本或值
    删除字符串最后一个字符的几种方法
  • 原文地址:https://www.cnblogs.com/GraceSkyer/p/5778231.html
Copyright © 2020-2023  润新知