题目地址: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;
}
本文介绍了一道经典的图论题目——寻找特定数量的蓝色边生成树。通过并查集算法确定一个无向图中是否存在包含特定数量蓝色边的生成树。文章详细解释了解题思路及代码实现。
242

被折叠的 条评论
为什么被折叠?



