題意:一張個點條邊的無向無權圖,求以下算法計算最大獨立集的正確率:隨機一個排列,依次考慮排列中每一個點,如果不與任何一個獨立集中的點相鄰則將其加入獨立集。模。
顯然這是個計數問題。
顯然是個狀壓dp。
設表示當前已經考慮完了,算出最大獨立集大小爲的方案數。
枚舉接下來考慮的點,設及與其相鄰的點中未被考慮的點的集合爲。
因爲相鄰的關係是相互的,所以一定是中第一個被考慮的(廢話)
在考慮完後,剩下的個點可以在後面隨便放,並不影響後面的計算,所以認爲中的點都考慮了。
即
最終答案爲,其中爲真正的最大獨立集大小
複雜度
如果被卡常了可以在dp的時候順便把算出來,不用單獨再算
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
using namespace std;
const int MOD=998244353;
typedef long long ll;
inline int qpow(int a,int p)
{
int ans=1;
while (p)
{
if (p&1) ans=(ll)ans*a%MOD;
a=(ll)a*a%MOD;p>>=1;
}
return ans;
}
int fac[25],finv[25];
int g[25][25];
int T[25],cnt[1<<20],dp[25][1<<20];
int main()
{
for (int i=1;i<(1<<20);i++) cnt[i]=cnt[i^(i&-i)]+1;
int n,m;
scanf("%d%d",&n,&m);
fac[0]=1;
for (int i=1;i<=n;i++) fac[i]=(ll)fac[i-1]*i%MOD;
finv[n]=qpow(fac[n],MOD-2);
for (int i=n-1;i>=0;i--) finv[i]=(ll)finv[i+1]*(i+1)%MOD;
for (int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
--u,--v;
g[u][v]=g[v][u]=1;
}
for (int i=0;i<n;i++)
{
T[i]=1<<i;
for (int j=0;j<n;j++)
T[i]|=g[i][j]<<j;
}
dp[0][0]=1;
int ans=0;
for (int S=0;S<(1<<n);S++)
for (int i=0;i<=cnt[S];i++)
{
if (!dp[i][S]) continue;
ans=max(ans,i);
for (int j=0;j<n;j++)
if (!(S&(1<<j)))
dp[i+1][S|T[j]]=(dp[i+1][S|T[j]]+(ll)dp[i][S]*fac[n-cnt[S]-1]%MOD*finv[n-cnt[S|T[j]]])%MOD;
}
printf("%lld\n",(ll)dp[ans][(1<<n)-1]*finv[n]%MOD);
return 0;
}