UCIPC2012-Red/Blue Spanning Tree解题报告

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4263

杭电热身赛的题,属于简单题,两次Kruskal算法,先把所有的红边加完,红边可以保证一部分的图是联通的,然后加蓝边构成生成树,那么这些蓝边就是整个生成树当中必须要有的边(其实不是因为这些边必须要有,因为这些边连的点必须要加到生成树里,所以必须要有一定数量的蓝边,可能这些蓝边的选择方案有很多,但是数量是一定的),然后把图还原,把原来必须的蓝边先加上,再一直加没有用过的蓝边,最后看加的蓝边的数量是不是>=k如果满足则能有方案做到,否则不能。

View Code
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #define N 1005
  5 using namespace std;
  6 int f[N];
  7 int n;
  8 bool used[N*N];
  9 struct edge
 10 {
 11     int u,v;
 12 };
 13 void init()
 14 {
 15     int i;
 16     for(i=1;i<=n;i++)
 17     f[i]=i;
 18     memset(used,0,sizeof(used));
 19 }
 20 int find(int i)
 21 {
 22     if(i!=f[i])
 23     {
 24         f[i]=find(f[i]);
 25     }
 26     return f[i];
 27 }
 28 void uni(int x,int y)
 29 {
 30     int t1=find(x);
 31     int t2=find(y);
 32     if(t1!=t2)
 33     f[t2]=t1;
 34 }
 35 edge R[N*N],B[N*N];
 36 int main()
 37 {
 38     int m,k,i,j,a,b;
 39     char s[2];
 40     int cnt1,cnt2;
 41     while(scanf("%d%d%d",&n,&m,&k)&&(n||m||k))
 42     {
 43         cnt1=cnt2=0;
 44         init();
 45         for(i=1;i<=m;i++)
 46         {
 47             scanf("%s%d%d",s,&a,&b);
 48             if(s[0]=='R')
 49             {
 50                 R[cnt1].u=a;
 51                 R[cnt1++].v=b;
 52             }
 53             else
 54             {
 55                 B[cnt2].u=a;
 56                 B[cnt2++].v=b;
 57             }
 58         }
 59         if(cnt2<k)
 60         {
 61             printf("0\n");
 62             continue;
 63         }
 64         //printf("%d %d\n",cnt1,cnt2);
 65         for(i=0;i<cnt1;i++)
 66         {
 67             uni(R[i].u,R[i].v);
 68         }
 69         int num=0;
 70         int num1=0;
 71         for(i=0;i<cnt2;i++)
 72         {
 73             if(find(B[i].u)!=find(B[i].v))
 74             {
 75                 num++;
 76                 uni(B[i].u,B[i].v);
 77                 used[i]=true;
 78             }
 79         }
 80         if(num>k)//如果必须加的蓝边的数量>k那就意味着无解了
 81         {
 82             printf("0\n");
 83             continue;
 84         }
 85         for(i=1;i<=n;i++)
 86         {
 87             f[i]=i;
 88         }
 89         for(i=0;i<cnt2;i++)
 90         {
 91             if(used[i])
 92             {
 93                 uni(B[i].u,B[i].v);
 94             }
 95         }
 96         for(i=0;i<cnt2;i++)
 97         {
 98             if(!used[i]&&find(B[i].u)!=find(B[i].v))
 99             {
100                 num++;
101                 uni(B[i].u,B[i].v);
102             }
103         }
104         if(num>=k)
105         printf("1\n");
106         else
107         printf("0\n");
108     }
109     return 0;
110 }

 

转载于:https://www.cnblogs.com/caozhenhai/archive/2012/08/26/2657188.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值