JZOJ 3632. 【汕头市选2014】舞伴

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。

Solution

  • 这题一看 N20 就知道是状压DP啦!

  • f[i][s] 表示选了前 i 个男孩,已选女孩状态为 s 的方案数。

  • 显然可得: f[i][s]+=f[i1][s]

  • 每个男孩向是朋友的女孩转移即可,还可以开滚动节约空间。

  • 总时间复杂度为 O(2NN2)

Code

#include<cstdio>
#include<cstring>
using namespace std;
int roll;
int a[21],p[21];
int f[2][1<<20];
inline int read()
{
    int data=0; char ch=0;
    while(ch<'0' || ch>'9') ch=getchar();
    while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();
    return data;
}
int main()
{
    int n=read(),m=read();
    for(int i=p[0]=1;i<=n;i++) p[i]=p[i-1]*2;
    for(int i=f[0][0]=1;i<=n;i++)
    {
        roll=1^roll;
        memset(f[roll],a[0]=0,sizeof(f[roll]));
        for(int j=1;j<=n;j++)
            if(read()) a[++a[0]]=j;
        for(int s=0;s<p[n];s++)
            if(f[1^roll][s])
                for(int j=1;j<=a[0];j++)
                    if(!(s&(p[a[j]-1])))
                        f[roll][s|p[a[j]-1]]=(f[roll][s|p[a[j]-1]]+f[1^roll][s])%m;
    }
    printf("%d",f[roll][p[n]-1]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值