【汕头市选2014】舞伴(perm)

Description

N 个男孩,N 个女孩,男孩和女孩可能是朋友,也可能不是朋友。现在要组成N 对舞伴,要求每对舞

伴都是一男一女,且他们是朋友。

统计不同配对方案的数量,因为结果很大,所以只要求除以M 的余数。

Input

第1 行,2 个整数N,M。接下来N 行,每行N 个整数Aij,表示第i 个男孩和第j 个女孩的关系。如果他们是朋友,则Aij = 1,否则Aij = 0。

Output

1 个整数,表示所求的值。

Sample Input

3 1000000000

1 1 1

1 1 1

1 1 1

Sample Output

6

Data Constraint

• 对于50% 的数据,N <= 9;

• 对于100% 的数据,1 <= N <= 20, 1 <= M <= 10^9; 0 <= Aij <= 1。

思路

状压DP

不难看出,因为他们只有选和不选,所以情况有2^40,会炸。
但是,我们可以只枚举男生,女生就只有2^20,可以过。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[22][22],e[22],n,b[22],c[22];
struct node
{
    int x,y;
}k[1048576];
long long m,f[22][1048576];
bool cmp(node x,node y){return x.y<y.y;}
int main()
{
// freopen("perm.in","r",stdin);
// freopen("perm.out","w",stdout);
    e[0]=1;
    for(int i=1; i<=20; i++) 
    {
        e[i]=e[i-1]*2;
    }
    for(int i=1; i<=e[20]-1; i++)
    {
        k[i].x=i;
        for(int j=1; j<=20; j++)if((i&e[j-1])!=0) k[i].y++;
    }
    sort(k+1,k+1048576,cmp);
    for(int i=1; i<=e[20]-1; i++) if(k[i].y!=k[i-1].y) 
    {
        b[k[i].y]=i;
        c[k[i].y-1]=i-1;
    }
    c[20]=b[20];
    scanf("%d %lld",&n,&m);
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++) scanf("%d",&a[i][j]);
    f[0][0]=1;
    for(int i=1; i<=n; i++)
    {
        for(int j=b[i]; j<=c[i]; j++)
        {
            int s=k[j].x;
            for(int k=1; k<=n; k++)
            if(a[i][k])
            {
                if((s&e[k-1])!=0) 
                f[i][s]=(f[i][s]+f[i-1][s-e[k-1]])%m;
            }
        }
    }
    printf("%lld\n",f[n][e[n]-1]);
}
    原文作者:舞伴问题
    原文地址: https://blog.csdn.net/Eric1561759334/article/details/79208173
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞