C. 奇奇怪怪的魔法阵(未搞懂)

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C. 奇奇怪怪的魔法阵(未搞懂)相关的知识,希望对你有一定的参考价值。

C. 奇奇怪怪的魔法阵

题意:

n个点m条边,定义集合S为独立集,当且仅当任意x,y∈S,x与y之间没有边。空集也是独立集
现在对于每一个点的集合T,有多少子集为独立集
设N=0,1,…,n-1, A T = ∑ S ⊂ T [ S 是 独 立 集 ] A_{T}=\\sum_{S⊂T}[S是独立集] AT=ST[S]。对于每一个T⊂N,求出 A T A_T AT
1<=n<=26

题解:

看这个数据范围就很明显,复杂度是(1<<26),正好1s内
而且肯定是dp转移,但是还是不知道咋做,看了题解恍然大悟

设dp[msk]表示msk的子集内独立集的个数。开始考虑转移,在msk中随便选一个元素i。对于元素i有两种情况,考虑i在不在独立集里,如果不在的话,i号点对其他点是没有影响的,那么直接从dp[msk^(1<<i)]转移。如果在,i号点的所有邻居都不能在独立集里,设i号点及其邻居的节点集合为 n e t [ i ] net[i] net[i],这种情况就从 d p [ m s k ⨁ n e t [ i ] ] dp[msk⨁net[i]] dp[msknet[i]]转移即可
以上这是官方题集,我现在还有很大的疑惑?等想明白继续更新

代码:

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,m,x,y,msk[55],dp[(1<<26)+10],fun[(1<<25)+10],id,ans;
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=0;i<n;i++) msk[i]=1<<i;
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		msk[x]|=(1<<y);
		msk[y]|=(1<<x);
	}
	for (int i=0;i<n;i++) fun[1<<i]=i;
	dp[0]=1;
	for (int i=1;i<(1<<n);i++)
	{
		id=fun[i&(-i)];//获取1的最低位 
		/*
		i^(1<<id):当前i的状态中去掉第id个 
		
		*/ 
		dp[i]=dp[i^(1<<id)]+dp[i^(i&msk[id])];
		if (dp[i]>=mod) dp[i]-=mod;
	}
	for (int i=(1<<n)-1;i>=0;i--) ans=(233ll*ans+dp[i])%mod;
	printf("%d\\n",ans);
	return 0;
}

以上是关于C. 奇奇怪怪的魔法阵(未搞懂)的主要内容,如果未能解决你的问题,请参考以下文章

牛客挑战赛53 C.奇奇怪怪的魔法阵(状压)

后验概率和条件概率(未搞懂待续)

遇到的奇奇怪怪的问题

遇到的奇奇怪怪的问题

为什么使用 do while,大家见到的奇奇怪怪的代码.

奇奇怪怪的bug系列微信小程序