PKUWC2018 随机算法

Posted kong-ruo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PKUWC2018 随机算法相关的知识,希望对你有一定的参考价值。

给你一个$n$个点$m$条边的无向图,执行如下算法:

1.随机一个$1~n$的排列$P$

2.从$P$中按顺序一个一个将点加进独立集$S$里,始终保证$S$是独立集(即如果当前点和当前集合里的某个点相邻,就不加了)

求最后得到的$S$是原图的一个最大独立集的概率

$50% n leq 17$

$100% n leq 20$

sol:

先考虑部分分吧

很暴力的状压dp,$F[S1][S2]$表示选了$S1$中的点,当前最大独立集是$S2$的方案数,最后除以$n!$就可以了

转移是枚举每个点,所以复杂度是$O(n3^n)$的($S2$一定是$S1$的子集)

后面的做法有点神仙

我不会做啊QAQ

观察题面,我们可以把点分为“考虑过的”和“现在还没考虑到的”

我们用$F_{(S,i)}$表示考虑了$S$集合,当前最大独立集为$i$的方案数其实可以优化,因为我们发现对于一个集合$S$,它的最大独立集是确定的,我们可以用$g[S]$来记录它,这是状态就可以优化一维

 

转移的时候,枚举一下第一个加到独立集里的点$i$,删去$i$和与$i$相邻的点,用它更新$g[S]$,再更新一下$F_S$即可

根本不可做呀

嘤嘤嘤

技术分享图片
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == -)f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - 0;
    return x * f;
}
const int maxn = (1 << 20) + 10,mod = 998244353;
int n,m;
int a[21];
int dp[maxn],mx[maxn];
int fac[30],ifac[30];
inline int ksm(int x,int t)
{
    int res = 1;
    while(t)
    {
        if(t & 1)res = res * x % mod;
        x = x * x % mod;
        t = t >> 1;
    }
    return res;
}
inline int A(int n,int m)
{
    return fac[n] * ifac[n - m] % mod;
}
signed main()
{
    n = read(),m = read();
    for(int i=1;i<=m;i++)
    {
        int u = read() - 1,v = read() - 1;
        a[u] |= (1 << (v));
        a[v] |= (1 << (u));
    }int MAXSTATE = (1 << n) - 1;
    fac[0] = 1,ifac[0] = 1;ifac[1] = 1;
    for(int i=1;i<=29;i++)fac[i] = (fac[i - 1] * i) % mod,ifac[i] = ksm(fac[i],mod - 2);
    //for(int i=1;i<=20;i++)cout<<fac[i]<<" "<<ifac[i]<<endl;
    
    //for(int i=0;i<=n;i++)a[i] |= i;
    dp[0] = 1;
    for(int s=0;s<=MAXSTATE;s++)
        if(dp[s])
        {
            for(int i=0;i<n;i++)
                if (!(s>>i&1))
                {
                    int t = s | a[i] | (1 << i);
                    if(mx[t] < mx[s] + 1)mx[t] = mx[s] + 1, dp[t] = 0;
                    if(mx[t] == mx[s] + 1)
                        dp[t] = (dp[t] + dp[s] * A(n - __builtin_popcount(s) - 1,__builtin_popcount(a[i]) - __builtin_popcount(a[i] & s))) % mod;
                }
        }
    cout<<dp[MAXSTATE] * ifac[n] % mod;
}
View Code

 

以上是关于PKUWC2018 随机算法的主要内容,如果未能解决你的问题,请参考以下文章

PKUWC2018 随机算法

loj#2540. 「PKUWC2018」随机算法

「PKUWC 2018」随机算法 (60分部分分做法)

[LOJ#2540][PKUWC2018]随机算法(概率DP)

LOJ2540 [PKUWC2018] 随机算法 状压DP

Loj #2542. 「PKUWC2018」随机游走