ABC310D Peaceful Teams

ABC310D Peaceful Teams

洛谷[ABC310D] Peaceful Teams

题目大意

n n n个运动员以及 m m m对数,每对数为 A i A_i Ai B i B_i Bi,表示 A i A_i Ai B i B_i Bi不能分在同一小组。你需要将这些人分为 t t t个小组,每个小组不能为空。

求分组的方案数。当一个划分中有两个运动员属于同一个队伍,而在另一个划分中属于不同的队伍时,这两个划分是不同的。

1 ≤ n ≤ 10 , 0 ≤ m ≤ n ( n − 1 ) 2 1\leq n\leq 10,0\leq m\leq \dfrac{n(n-1)}{2} 1n10,0m2n(n1)


题解

用状压DP。

f i , s f_{i,s} fi,s表示当前已经选择的运动员的状态为 s s s,这些运动员分成了 i i i组。则转移式为

f i , s = ∑ f i − 1 , s ⊕ j f_{i,s}=\sum f_{i-1,s\oplus j} fi,s=fi1,sj

其中 j j j满足 j & s = j j\& s=j j&s=j j j j中状态为 1 1 1的运动员中不存在两个不能分在同一个小组的运动员。

j j j是否满足后面的条件可以 O ( m 2 n ) O(m2^n) O(m2n)预处理出,而因为 s s s包含于 2 n − 1 2^n-1 2n1 j j j包含于 s s s,所以枚举 s s s j j j的次数为 3 n 3^n 3n(每个运动员只有三种情况:不在 s s s中、在 s s s中但不在 j j j中,在 s s s中也在 j j j中)。

注意当每个小组成员不变的情况下,会将一种情况计算 t ! t! t!次,所以答案为 f t , 2 n − 1 t ! \dfrac{f_{t,2^n-1}}{t!} t!ft,2n1

时间复杂度为 O ( m 2 n + t 3 n ) O(m2^n+t3^n) O(m2n+t3n)

code

#include
using namespace std;
int n,t,m,a[105],b[105],z[2005];
long long ans,f[15][2005];
int main()
{
	scanf("%d%d%d",&n,&t,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&a[i],&b[i]);
	}
	for(int s=0;s<1<<n;s++){
		z[s]=1;
		for(int k=1;k<=m;k++){
			if((s&(1<<a[k]-1))&&(s&(1<<b[k]-1))){
				z[s]=0;break;
			}
		}
	}
	f[0][0]=1;
	for(int i=1;i<=t;i++){
		for(int s=1;s<1<<n;s++){
			for(int j=s;j>=1;j=(j-1)&s){
				if(z[j]) f[i][s]+=f[i-1][s^j];
			}
		}
	}
	ans=f[t][(1<<n)-1];
	for(int i=1;i<=t;i++) ans/=i;
	printf("%lld",ans);
	return 0;
}

你可能感兴趣的:(题解,题解,c++)