C. 奇奇怪怪的魔法阵
题意:
n个点m条边,定义集合S为独立集,当且仅当任意x,y∈S,x与y之间没有边。空集也是独立集
现在对于每一个点的集合T,有多少子集为独立集
设N=0,1,…,n-1,AT=∑S⊂T[S是独立集]A_{T}=\sum_{S⊂T}[S是独立集]AT=∑S⊂T[S是独立集]。对于每一个T⊂N,求出ATA_TAT
1<=n<=26
题解:
看这个数据范围就很明显,复杂度是(1<<26),正好1s内
而且肯定是dp转移,但是还是不知道咋做,看了题解恍然大悟
设dp[msk]表示msk的子集内独立集的个数。开始考虑转移,在msk中随便选一个元素i。对于元素i有两种情况,考虑i在不在独立集里,如果不在的话,i号点对其他点是没有影响的,那么直接从dp[msk^(1<<i)]转移。如果在,i号点的所有邻居都不能在独立集里,设i号点及其邻居的节点集合为net[i]net[i]net[i],这种情况就从dp[msk⨁net[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;
}