题目描述
给定一张有 nn个点 mm条边的图,生成 1∼n1\sim n的全排列,假设一个排列是 pp, SS是当前最大独立集;如果 S∪pi是独立集就令 S=S∪piS=S\cup {p_i} ;求这 n!n!个独立集有多少个为最大独立集,答案对 998244353取模。
输入输出格式
输入格式:
第一行两个整数 n,mn,m 接下来 mm 行,每行两个整数 x,yx,y,表示 x,yx,y之间有边
输出格式:
一行,即总个数
输入输出样例
5 4 1 2 2 3 3 4 4 5
56
说明
n<=20,m<=400
暴力枚举所有排列大概是30分
可以这样
$f[S_1][S_2]$表示第前几个点加入独立集的状态为$S_1$,未加入为$S_2$
复杂度大概是$O(n*4^{n})$
但我们发现实际上第二维没什么用
我们令一个独立集所有的相邻点为相邻点集
那么如果要在数列中放相邻点集,那么显然无所谓放哪个,反正没有影响
如果选了非相邻点集,那么相邻点集显然会在原来基础上扩大
于是我们设
$f[S][k]$表示独立集状态为S,选了k个相邻点
$t[S]$表示S状态有多少相邻点
那么转移分两种:
1.选相邻点:
$f[S][k+1]+=f[S][k]*(t[S]-k)$
2.选独立点
$f[S|(1<<i)][k]+=f[S][k]$
于是复杂度就变成了$O(n^{2}*2^{n})$且常数很小
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int f[1<<21][21],ans,n,m,vv[21],vis[21],t[1<<21],s[1<<21],pd[1<<21],o[1<<21],pw[21],num[1<<21],Mod=998244353,Max,cnt,p[1<<21]; 8 int main() 9 {int i,j,u,v,flag,l,k; 10 cin>>n>>m; 11 for (i=1;i<=n;i++) 12 pw[i]=1<<(i-1); 13 for (i=1;i<=m;i++) 14 { 15 scanf("%d%d",&u,&v); 16 s[u]|=pw[v]; 17 s[v]|=pw[u]; 18 } 19 for (i=0;i<(1<<n);i++) 20 { 21 int tmp=0; 22 pd[i]=1; 23 for (j=1;j<=n;j++) 24 if ((pw[j]&i)&&(s[j]&i)) pd[i]=0; 25 if (pd[i]) 26 { 27 tmp=0; 28 for (j=1;j<=n;j++) 29 if (i&pw[j]) 30 o[i]|=s[j],tmp++; 31 num[i]=tmp; 32 tmp=0; 33 for (j=1;j<=n;j++) 34 if (o[i]&pw[j]) 35 tmp++; 36 t[i]=tmp; 37 } 38 } 39 f[0][0]=1; 40 for (i=0;i<(1<<n);i++) 41 if (pd[i]) 42 { 43 for (k=0;k<=t[i];k++) 44 { 45 for (j=1;j<=n;j++) 46 if (!(i&(1<<j-1))) 47 { 48 if (!(i&p[i])) 49 f[i|(1<<j-1)][k]=(f[i|(1<<j-1)][k]+f[i][k])%Mod; 50 } 51 if (k!=t[i]) 52 { 53 f[i][k+1]+=1ll*f[i][k]*(t[i]-k)%Mod; 54 f[i][k+1]%=Mod; 55 } 56 } 57 } 58 Max=0;ans=0; 59 for (i=0;i<(1<<n);i++) 60 { 61 cnt=num[i]; 62 if (cnt>Max) 63 { 64 Max=cnt; 65 ans=f[i][t[i]]; 66 ans%=Mod; 67 } 68 else if (cnt==Max) 69 { 70 ans+=f[i][t[i]]; 71 ans%=Mod; 72 } 73 } 74 cout<<ans; 75 }
给定一张有n个点m条边的图,生成1-n的全排列,假设一个排列是p,S是当前最大独立集;如果S∪{pi}是独立集就令S=S∪{pi};求这n!
个独立集是最大独立集的概率,答案对998244353取膜。