题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2208
题目大意:
有n个小朋友,之间有相互喜欢的关系,如果A喜欢B的话,输入时保证B一定喜欢A。现在有m个小气球,问能否分成不超过m组,每组不存在有两个小朋友互相不喜欢。
解题思路:
因为不具有传递性,所以不属于双联通。
又n很小,所以直接暴搜。
fa[i]=j表示i是属于j为根的集合。 不能用贪心,先把一个小朋友的满足的最大的朋友全部去掉。。。这种思路是错的,要全局搜索。
代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
#define Maxn 15
int fa[Maxn];
bool edge[Maxn][Maxn];
int n,m;
bool dfs(int a,int mm) //a表示第几个小朋友,mm表示前面用了多少个气球
{
if(mm>m)
return false;//气球用超了
if(a==n)//表示小朋友已经安排完了
return true;
for(int i=0;i<a;i++) //扫描前面有多少个集合
{
if(fa[i]!=i)
continue;
bool flag=true;
for(int j=0;j<a&&flag;j++)
if(fa[j]==i)
flag=edge[j][a];
if(flag)
{
fa[a]=i;
if(dfs(a+1,mm))
return true; //往后扫
fa[a]=a;//不放到该集合里去
}
}
if(dfs(a+1,mm+1)) //单独作为一个集合
return true;
return false;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(edge,false,sizeof(edge));
for(int i=0;i<n;i++)
{
int k,a;
scanf("%d",&k);
for(int j=0;j<k;j++)
scanf("%d",&a),edge[i][a]=true;
}
for(int i=0;i<n;i++)
fa[i]=i;
if(m>=n||dfs(0,0))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}