洛谷P4547 [THUWC2017]随机二分图

题目描述

题解

考虑一个完美匹配出现的概率 $\times 2^n$ 对答案的贡献,初始是 $1$ ,如果有出现一组 $t=2$ 的边的话,那贡献就是 $0$ ,否则每出现一组 $t=1$ 的边就要 $\times 2$ ,所以有个暴力的 $\text{dp}$ : $f[s1][s2]$ 表示左边出现点的状态为 $s1$ ,右边为 $s2$ 的答案,为了避免重复我们每次挑 $s1$ 中编号最小的点进行转移,即 $f[s1][s2]=\sum_{y \in s2}f[s1 \wedge x][s2 \wedge y]$ ,考虑如果 $(x,y)$ 有一组 $t=1$ 的边 $(u,v)$ 也在 $s1,s2$ 集合中的话,那要再加上 $f[s1 \wedge x \wedge u][s2 \wedge y \wedge v]$ ,反之如果有一组 $t=2$ 的在集合中的话就要扣掉,记忆化搜索即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int P=1e9+7;map<int,int>f;
int n,m,k,a[15][15],c[1<<15],b[15][15][2];
int X(int x){return x>=P?x-P:x;}
int F(int i,int j){
    if (f.count(i<<n|j)) return f[i<<n|j];
    int w=0,x=i&-i,u,v;
    for (int y=j&-j,k=j;k;k^=y,y=k&-k){
        if (!~a[c[x]][c[y]]) continue;
        w=X(w+F(i^x,j^y));
        u=b[c[x]][c[y]][0];v=b[c[x]][c[y]][1];
        if (a[c[x]][c[y]] && (u&i) && (v&j) && u!=x && v!=y){
            if (a[c[x]][c[y]]&1) w=X(w+F(i^x^u,j^y^v));
            else w=X(w+P-F(i^x^u,j^y^v));
        }
    }
    return f[i<<n|j]=w;
}
int main(){
    cin>>n>>m;k=1<<n;
    for (int i=0;i<n;i++) c[1<<i]=i;
    memset(a,-1,sizeof a);
    for (int x,y,u,v,o,i=1;i<=m;i++){
        scanf("%d%d%d",&o,&x,&y);
        x--;y--;a[x][y]=o;
        if (o){
            scanf("%d%d",&u,&v);
            u--;v--;a[u][v]=o;
            b[x][y][0]=1<<u;b[x][y][1]=1<<v;
            b[u][v][0]=1<<x;b[u][v][1]=1<<y;
        }
    }
    f[0]=1;
    printf("%d\n",F(k-1,k-1));
    return 0;
}

 

上一篇:树上问题乱做


下一篇:笔记 - 最短路