【BZOJ】5006: [THUWC2017]Bipartite 随机二分图-状压DP

传送门:bzoj5006


题解

状压 S S S表示左右部分别选了哪些点构成完美匹配, m a p map map记忆化 f [ S ] f[S] f[S]表示 S S S点集完美匹配的方案数 × 2 ∣ S ∣ 2 \times 2^{\frac{|S|}{2}} ×22S(显然 ∣ S ∣ |S| S为偶数)。

为了减少状态数并避免重复计算,枚举左部中 l o w b i t lowbit lowbit连向的右部的点:

对于0的情况,转移系数 2 × 50 % = 1 2\times 50\%=1 2×50%=1,直接转移即可。

对于1,2的情况,首先将两条边分别看做0的情况直接转移;仅当两条边同时选入完美匹配时概率不对,那么判断 S S S中是否可以同时选这两条边,强制选另一条边进行转移,系数 2 × 2 × 25 % = 1 2\times 2\times 25\%=1 2×2×25%=1,1的情况加上,2的情况减去即可。

复杂度 O ( 能 过 ) O(能过) O()


代码

#include<bits/stdc++.h>
#define rc(a,b) (((a)<<15)|(b))
using namespace std;
typedef long long ll;
const int N=(1<<15)+10,mod=1e9+7,M=15;

int n,m,typ[M][M],s[N],S;

struct P{
	int tp;
	int ax,ay,bx,by;
}p[300];

map<int,int>f;

inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline void dc(int &x,int y){x-=y;if(x<0) x+=mod;}

int cal(int a,int b)
{
	if(f.find(rc(a,b))!=f.end()) return f[rc(a,b)];
	int i,x=a&(-a),y,t=b,re=0,c,d;
	for(y=t&(-t);t;y=t&(-t)){
	  t^=y;
	  if((i=typ[s[x]][s[y]])){
		 ad(re,cal(a^x,b^y));
		 if(!p[i].tp) continue;
		 ((x==p[i].ax)&&(y==p[i].ay))?(c=p[i].bx,d=p[i].by):(c=p[i].ax,d=p[i].ay);
		 if((c!=x)&&(d!=y)&&(a&c)&&(b&d)){
		 	d=cal(a^x^c,b^y^d);
		 	(p[i].tp==1)?ad(re,d):dc(re,d);
		 }
	  }
	} 
	f[rc(a,b)]=re;
	return re;
}

int main(){
	int i,j,x,y;
	scanf("%d%d",&n,&m);S=(1<<n)-1;
	for(i=1;i<=m;++i){
		scanf("%d",&p[i].tp);
		scanf("%d%d",&x,&y);x--;y--;
		typ[x][y]=i;
		if(p[i].tp){
			p[i].ax=1<<x;p[i].ay=1<<y;
			scanf("%d%d",&x,&y);x--;y--;
		    typ[x][y]=i;p[i].bx=1<<x;p[i].by=1<<y;
		}
	}
	for(i=0;i<n;++i) s[1<<i]=i;f[0]=1;
	printf("%d",cal(S,S));
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值