给定N个城市的家庭,第i个城市有ai个家庭参与,每个家庭要派一个成员到其它家庭去,同时接收一个,唯一的限制是不能去同一城市的家庭,问有多少种合理的交换方案。
题目说明了总家庭数量不超过15。
可以看成是棋盘覆盖问题(最大就15*15的棋盘),行表示第i个家庭派出的成员,列表示目标的家庭,mat[i][j]用01两个状态标记,表示第i个家庭的成员能否到第j个家庭去。
然后就是状态压缩DP一下了。
#include<cstdio>
#include<cstring>
typedef long long LL;
LL dp[2][1<<15];
int id[20];
bool mat[20][20];
int main(){
int n, m, a;
while(~scanf("%d", &n)){
m = 0;
for(int i=0; i<n; i++){
scanf("%d", &a);
int x = m;
m+=a;
for(int j=x; j<m; j++) id[j]=i;
}
memset(mat,0,sizeof(mat));
for(int i=0; i<m; i++){
for(int j=0;j<m;j++){
if(id[i]!=id[j]) mat[i][j]=1;
}
}
memset(dp,0,sizeof(dp));
bool f=0;
dp[0][0] = 1;
for(int i=0; i<m; i++){
for(int j=0; j<(1<<m); j++){
if(dp[f][j]==0) continue;
for(int k=0; k<m; k++){
if((j&(1<<k)) || !mat[i][k]) continue;
dp[f^1][j|(1<<k)]+=dp[f][j];
}
}
memset(dp[f],0,sizeof(dp[f]));
f^=1;
}
printf("%lld\n", dp[f][(1<<m)-1]);
}
return 0;
}