C. 奇奇怪怪的魔法阵(未搞懂)
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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=∑S⊂T[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[msk⨁net[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. 奇奇怪怪的魔法阵(未搞懂)的主要内容,如果未能解决你的问题,请参考以下文章