链接: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 }