题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4263
/*
=====================================
Author:Bob Lee
2012.8.27
=====================================
这道题目的意思很简单
给你一个无向图,确保这个图是有生成树的
但是这个图的边要么是blue,要么是red
现在给你个参数k,问你是否在这个图中是否存在一个生成树
恰好有k条蓝色的边。
注意题目要求的是生成树
当时打比赛的时候想得太复杂,现在一想当时自己真的是弱爆了
把生成树最少用几条蓝边的数量算出来
最多可以有多少算出来
然后看k是不是在这个中间就OK了
利用并查集就可以解决,但是有一个生成树的概念也要弄清楚
*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
#define MAXN 1010
int n,m,k;
int father[MAXN];
int map[MAXN][MAXN];
void init_father()
{
int i;
for(i=1;i<=n;i++)
father[i] = -1;
}
int find(int x)
{
int s;
for(s=x;father[s]>=0;s=father[s]);
while(s!=x) //这里用到的是所谓的路径压缩,方便后面的查找
{
int t = father[x];
father[x] = s;
x = t;
}
return s;
}
void Union(int x,int y)
{
int x1 = find(x);
int y1 = find(y);
int tmp = father[x1]+father[y1]; //这里是两个集合的总个数(负数)
if(father[x1] > father[y1]) //采用这样的合并判断,也是为了减少深度
{
father[x1] = y1;
father[y1] = tmp;
}
else
{
father[y1] = x1;
father[x1] = tmp;
}
}
void build_map()
{
int i;
char s[2];
int a,b,c;
for(i=1;i<=m;i++)
{
scanf("%s%d%d",s,&a,&b);
if(s[0] == 'B')
c = 1;
else
c = 0;
map[a][b] = map[b][a] = c;
}
//cout<<"build"<<endl;
}
int main()
{
while(scanf("%d%d%d",&n,&m,&k) != EOF && n+m+k)
{
init_father();
memset(map,-1,sizeof(map));
build_map();
int num = 0;
int i,j;
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
if(map[i][j] == 0 && find(i) != find(j))
{
Union(i,j);
num++;
}
}
}
//cout<<"for red"<<endl;
int ans1 = n - num - 1;
num = 0;
init_father();
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
if(map[i][j] == 1 && find(i) != find(j))
{
Union(i,j);
//cout<<i
num++;
}
}
}
//cout<<"for blue"<<endl;
int ans2 = num;
if(k>=ans1 && k<=ans2)
cout<<1<<endl;
else
cout<<0<<endl;
}
return 0;
}