Description
由于计算机系的同学们都很宅,很多同学虽然身在一个系,但是入学很久还是相互不认识。学生会主席小Y希望举办一次破冰派对,要让同学们多从寝室里走出来参加娱乐活动,也要让尽量多不认识的同学们通过活动相互认识。自然的,如果参加活动的同学互相都不认识,那便是极好的。?
要办一次成功的派对是很不容易的,不光需要有同学参加,优秀的工作人员也是必不可少的。他们需要为派对的筹办付出很多的努力,因此一个和谐的团队是非常重要的。小Y希望所有工作人员都是相互认识的。
计算机系一共有N个同学,所有同学从1到N编号。有M对同学相互认识,而其余的同学相互不认识。
小Y希望从中选出一些工作人员组成工作团队,让这个工作团队负责活动的组织,而其余的所有非工作人员,就自然都成为了活动的参与者。小Y要求:
1、工作团队的成员必须相互认识;
2、参与活动的同学必须相互不认识;
3、至少有一个同学参与活动,也至少有一个同学是工作人员。
小Y想知道,一共有多少种工作团队的选择方案呢?
Solution
这题一开始分析了一下,觉得方案好像不是很多,因为限制很多,但是看到有个模数,以为会很多,但其实这个模数是假的……
而且单独求最大团是个NPC问题,是只能搜的,现在这题加了个限制,其实也只能搜。但是我比较辣鸡没敢写。
说一下剪枝吧。一开始先把一些必须工作或参与活动的人选出来,然后把这些已经确定的点删掉,得到很多连通块,最多只有一个是多于一个点的,否则无解(这个显然),只用在那个里面搜就行了。如果全部连通块都是一个点的,那么方案数就是连通块数
+
1
+1
+1。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=1010;
const int mod=1000003;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,m,ans,tmp[Maxn],lt;bool mark[Maxn];
bitset<Maxn>f[Maxn],c[2],z;
struct Edge{int y,next;}e[Maxn*Maxn<<1];
int last[Maxn],len;
void ins(int x,int y)
{
int t=++len;
e[t].y=y;e[t].next=last[x];last[x]=t;
}
int p[Maxn];//-1不确定 0工作 1活动
void dfs(int x)
{
if(x==n+1){if(c[1]!=z&&c[0]!=z)ans++;if(ans>=mod)ans-=mod;return;}
if(p[x]!=-1){dfs(x+1);return;}
if((f[x]&c[0])==c[0])p[x]=0,c[0].set(x),dfs(x+1),p[x]=-1,c[0].set(x,0);
if((f[x]&c[1])==z)
{
for(int i=last[x];i;i=e[i].next)if((f[e[i].y]&c[0])!=c[0])return;
for(int i=last[x];i;i=e[i].next)p[e[i].y]=0,c[0].set(e[i].y);
p[x]=1,c[1].set(x);
dfs(x+1);
for(int i=last[x];i;i=e[i].next)p[e[i].y]=-1,c[0].set(e[i].y,0);
p[x]=-1,c[1].set(x,0);
}
}
int main()
{
int T=read();z.reset();
while(T--)
{
n=read(),m=read();
if(!m)
{
if(n==1)puts("0");
else printf("%d\n",n);
continue;
}
memset(last,0,sizeof(last));len=ans=0;
memset(p,-1,sizeof(p));memset(mark,false,sizeof(mark));
c[0].reset(),c[1].reset();
for(int i=1;i<=n;i++)f[i].reset();
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
ins(x,y),ins(y,x);f[x].set(y);f[y].set(x);
}
for(int i=1;i<=n;i++)f[i].set(i);
bool no=false;
for(int x=1;x<=n;x++)
{
bool flag=false;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if((f[y]&f[x])!=f[x]){flag=true;break;}
}
if(flag)
{
if((f[x]&c[0])!=c[0]){no=true;break;}
p[x]=0,c[0].set(x),mark[x]=true;
}
}
if(no){puts("0");continue;}
for(int x=1;x<=n;x++)
if(p[x]==-1&&(f[x]&c[0])!=c[0])
{
p[x]=1;
if((f[x]&c[1])!=z){no=true;break;}
c[1].set(x),mark[x]=true;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(p[y]==1){no=true;break;}
if((f[y]&c[0])!=c[0]){no=true;break;}
p[y]=0;mark[y]=true;
}
if(no)break;
}
if(no){puts("0");continue;}
lt=0;int c0=0;bool all=true;
for(int x=1;x<=n;x++)
{
if(p[x]==0)c0++;
if(mark[x])continue;
int cnt=0;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(!mark[y])cnt++;mark[y]=true;
}
if(cnt)all=false;++lt;
}
if(all){printf("%d\n",lt+(c0!=0));continue;}
dfs(1);
printf("%d\n",ans);
}
}