51nod 1833 环 (dp)

42 篇文章 0 订阅

虽然标题是图论,我感觉和图论有关系,但是和dp关系更密切。

我们发现这个不相交环其实就是把原图造成二分图的一个完全匹配。

比如如果有一个i->j的边我们就在i->j'的二分图中建一个边。
我们可以容易知道二分图的完全匹配就是不相交环覆盖的方案数。
那么就可以用集合dp在O(n2^n)中找出所有完全匹配就可以了。
就是枚举一下这个集合然后找一个固定元素出来求一下贡献就可以了。
转移时O(n)的状态集合数是O(2^n)的。


我们可以容易知道二分图的完全匹配就是不相交环覆盖的方案数。求这个方案数就是用dp来求,用图论复杂度可能会超限或者说麻烦点,

dp[i][j]表示第i位已经匹配了i个数,这i个数可以用二进制j表示,n个数每个数都匹配一个不是自身的数,就是全集(1<<n)-1.当然任意两个数不能匹配相同的数。不然结果为0,开始dp[0][0]=1。

细思极巧。

#include <bits\stdc++.h>
#include <math.h>
using namespace std;
const int mod=998244353;
vector<int>a[25];
int f[25][(1<<20)+5];
int main()
{
int n,m,u,v;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
a[u].push_back(v);
}
	f[0][0] = 1;
	for (int i = 1; i <= n; i ++){
		for (int j = 0; j < 1<<n; j ++)
			if (__builtin_popcount(j) == i){
				for (int k =0; k<a[i].size(); k++){
					int v = a[i][k];
					if ((j>>v-1)&1)
						f[i][j] = (f[i][j]+f[i-1][j^(1<<v-1)])%mod;
				}
				//cout<<i<<" "<<j<<" "<<f[i][j]<<endl; 输出看一下更容易理解
			}
	}
	printf("%d\n", f[n][(1<<n)-1]);
    return 0;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值