码迷,mamicode.com
首页 > 编程语言 > 详细

【PKUWC2018】随机算法

时间:2019-01-19 16:15:38      阅读:217      评论:0      收藏:0      [点我收藏+]

标签:意图   script   ret   接下来   algo   常用   ons   np完全   cup   

Description

我们知道,求任意图的最大独立集是一类NP完全问题,目前还没有准确的多项式算法,但是有许多多项式复杂度的近似算法。

例如,小 C 常用的一种算法是:

1.对于一个 \(n\) 个点的无向图,先等概率随机一个 \(1\ldots n\) 的排列 \(p[1\ldots n]\)

2.维护答案集合 \(S\) ,一开始 \(S\) 为空集,之后按照 \(i=1\ldots n\)的顺序,检查 \(\{p[i]\}\cup S\) 是否是一个独立集,如果是的话就令 \(S=\{p[i]\}\cup S\)

3.最后得到一个独立集 \(S\) 作为答案。

小 C 现在想知道,对于给定的一张图,这个算法的正确率,输出答案对 \(998244353\) 取模

Input

第一行两个非负整数 \(n,m\) 表示给定的图的点数和边数。

接下来 \(m\) 行,每行有两个正整数 \((u,v) (u\neq v)\)描述这张图的一条无向边。

Output

输出正确率,答案对 \(998244353\) 取模。

Solution

看到\(n \leq 20\) 时,有经验的选手应该就会往状压DP上去想.

\(F_{i,j}\)表示当前独立集大小为i,不能选的点集为j的方案数,\(S_u\)表示选了\(i\)后不能选的点的集合,易得

\[ F_{i,j\bigcup S_u}=F_{i,j\bigcup S_u}+F_{i-1,j}*A_{n-\mid j \mid -1}^{\mid j\bigcup S_u \mid - \mid j \mid -1 } u \notin j\]

复杂度 \(O(2^n * n^2)\),这看起来已经很优秀了。

继续观察,发现每个状态的最大独立集是唯一的

\(S_j\)表示不能选的点集为j时最大的独立集大小

每次更新\(S_j\)时将\(F_j\)清零即可

复杂度变为\(O(2^n*n)\)

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int Mod=998244353;
int n,m,cou[1500000],state[50],num[1500000];
long long J[50],dp[1500000],R[50];
long long fpow(long long a,int k)
{
    long long ans=1;
    while (k)
    {
        if (k&1) ans=ans*a%Mod;
        a=a*a%Mod;
        k>>=1;
    }
    return ans;
}
long long A(int n,int m)
{
    return (n>=m?J[n]*R[n-m]%Mod:0);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<(1<<n);i++) cou[i]=cou[i>>1]+(i&1);
    for (int i=1;i<=n;i++) state[i]|=1<< i-1;
    for (int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        state[u]|=1<< v-1;
        state[v]|=1<< u-1;
    }
    J[0]=1;
    for (int i=1;i<=n;i++) J[i]=J[i-1]*i%Mod;
    for (int i=0;i<=n;i++) R[i]=fpow(J[i],Mod-2);
    dp[0]=1;num[0]=0;
    for (int i=0;i<(1<<n);i++)
    {
        if (!dp[i]) continue;
        for (int j=1;j<=n;j++)
        {
            if ((i>>(j-1)) & 1) continue;
            if (num[i]+1>num[i|state[j]]) num[i|state[j]]=num[i]+1,dp[i|state[j]]=0;
            if (num[i]+1==num[i|state[j]]) dp[i|state[j]]=(dp[i|state[j]]+dp[i]*A(n-cou[i]-1,cou[i|state[j]]-cou[i]-1)%Mod)%Mod;
        }
    }
    printf("%lld\n",dp[(1<<n)-1]*fpow(J[n],Mod-2)%Mod);
    return 0;
}

【PKUWC2018】随机算法

标签:意图   script   ret   接下来   algo   常用   ons   np完全   cup   

原文地址:https://www.cnblogs.com/Code-Geass/p/10291705.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!