状压DP。。。
一个人和猫的DP,一个是狗和猫的DP。
人和猫的DP复杂度是n^2*(1<<m),狗和猫的复杂度是n^3*(1<<m);
因为n个人都是要用完的按顺序DP即可,但是狗不一定要用完,要计算对应n的数量的狗的方案数
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
bool cant1[11][11], cant2[11][11];
long long dp1[11][1130], dp2[11][1130];
int main()
{
int i, j, k, r, n, m, p, q, a, b;
while(~scanf("%d%d%d",&n,&m,&p)){
memset(cant1,0,sizeof(cant1));
memset(cant2,0,sizeof(cant2));
scanf("%d",&q);
for(i=1;i<=q;i++){
scanf("%d%d",&a,&b);
if(b<=n+m&&b>=n+1) swap(a,b);
a-=n;
if(b>=n+m+1){
cant2[b-n-m-1][a-1]=1;
}else{
cant1[b-1][a-1]=1;
}
}
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
int all=1<<m;
dp1[0][0]=dp2[0][0]=1;
for(i=1;i<=n;i++){
for(j=0;j<all;j++){
if(!dp1[i-1][j]) continue;
for(k=0;k<m;k++){
if(j&(1<<k)||cant1[i-1][k]) continue;
dp1[i][j|(1<<k)]+=dp1[i-1][j];
}
}
}
for(i=1;i<=p;i++){
for(r=p;r>=1;r--){
for(j=0;j<all;j++){
if(!dp2[r-1][j]) continue;
for(k=0;k<m;k++){
if(j&(1<<k)||cant2[i-1][k]) continue;
dp2[r][j|(1<<k)]+=dp2[r-1][j];
}
}
}
}
long long ans=0;
for(j=0;j<all;j++)
ans+=dp1[n][j]*dp2[n][j];
printf("%lld\n",ans);
}
return 0;
}