题解 P4547 【[THUWC2017]随机二分图】
根据题意,题目中所求的即为所有
发现
其中
发现直接这样转移会算重,所以要事先固定一种转移顺序,可以是每次在
然后考虑如何解决每条边的出现概率,第一组边不用特殊考虑,概率为
第二组和第三组边中,若两条边有交集,即两条边为一个点连向另外两个点,此时是不用加上同时选这两条边的情况的,因为题目所求为完美匹配,一个点匹配两个点的情况是不存在的。
处理完边后,记忆化搜索来实现状压
#include<bits/stdc++.h>
#define maxs 70010
#define p 1000000007
#define inv2 500000004
#define inv4 250000002
#define sta(x) (1<<(x-1))
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,m,cnt;
map<int,ll> f[maxs];
struct node
{
ll s,t,v;
}e[maxs];
ll dp(int S,int T)
{
if(!S) return 1;
if(f[S].count(T)) return f[S][T];
for(int i=1;i<=cnt;++i)
{
ll s=e[i].s,t=e[i].t,v=e[i].v;
if((S|s)!=S||(T|t)!=T||S>=(s<<1)) continue;
f[S][T]=(f[S][T]+dp(S^s,T^t)*v%p)%p;
}
return f[S][T];
}
int main()
{
read(n),read(m);
for(int i=1;i<=m;++i)
{
int opt,x,y;
read(opt),read(x),read(y),e[++cnt]=(node){sta(x),sta(y),inv2};
if(opt)
{
read(x),read(y);
if(!((sta(x)&e[cnt].s)||(sta(y)&e[cnt].t)))
{
cnt++;
if(opt==1) e[cnt]=(node){sta(x)|e[cnt-1].s,sta(y)|e[cnt-1].t,inv4};
else e[cnt]=(node){sta(x)|e[cnt-1].s,sta(y)|e[cnt-1].t,p-inv4};
}
e[++cnt]=(node){sta(x),sta(y),inv2};
}
}
printf("%lld",dp((1<<n)-1,(1<<n)-1)*(1<<n)%p);
return 0;
}