「PKUWC2018」随机算法

本文探讨了求解图的最大独立集问题的近似算法,介绍了一种基于随机排列的算法及其正确率的计算方法。通过枚举排列中的元素状态,计算不同状态下的准确率,最终得出算法在给定图上的期望正确率。

传送门

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\)取模

Solution

其实并没有很难。

\(f[S]\)表示当前排列中的元素状态为\(S\)时的准确率,\(g[S]\)表示它的最大独立集大小。

我们不妨枚举\(S\)排列的第\(1\)个数\(j\),从\(S\)中去掉包括\(j\)在内的所有与\(j\)有关联的点得到集合\(S'\),显然,若\(S\)排列的第\(1\)个数为\(j\),它的准确率就是\(f[S']\)。所以:

\[f[S]=\frac{\sum f[S']}{|S|}\]

最后答案就是\(f[U]\)


Code 

//2019.1.16 8:24~9:20 PaperCloud
#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define mod 998244353
int N,f[1<<20],g[1<<20],s[20],inv[22];
int main()
{
    register int n=read(),m=read(),i,j,cnt,k;
    while(m--) i=read()-1,j=read()-1,s[i]|=1<<j,s[j]|=1<<i;
    for(i=0;i<n;++i) s[i]|=1<<i;
    for(inv[1]=f[0]=1,i=2;i<=n;++i) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod; 
    for(N=1<<n,i=1;i<N;f[i]=1ll*f[i]*inv[cnt]%mod,++i)
        for(cnt=j=0;j<n;++j)if(i>>j&1)
        {
            cnt++;g[i]<g[k=i&(~s[j])]+1?(g[i]=g[k]+1,f[i]=0):0;
            g[i]==g[k]+1?(f[i]+=f[k])%=mod:0;
        }
    return 0*printf("%d\n",f[N-1]);
}



Blog来自PaperCloud,未经允许,请勿转载,TKS!

转载于:https://www.cnblogs.com/PaperCloud/p/10275265.html

# P5298 [PKUWC2018] Minimax ## 题目描述 小 $C$ 有一棵 $n$ 个结点的有根树,根是 $1$ 号结点,且每个结点最有两个子结点。 定义结点 $x$ 的权值为: 1.若 $x$ 没有子结点,那么它的权值会在输入里给出,**保证这类点中每个结点的权值互不相同**。 2.若 $x$ 有子结点,那么它的权值有 $p_x$ 的概率是它的子结点的权值的最大值,有 $1-p_x$ 的概率是它的子结点的权值的最小值。 现在小 $C$ 想知道,假设 $1$ 号结点的权值有 $m$ 种可能性,**权值第 $i$ 小**的可能性的权值是 $V_i$,它的概率为 $D_i(D_i>0)$,: $$\sum_{i=1}^{m}i\cdot V_i\cdot D_i^2$$ 你需要输出答案对 $998244353$ 取模的值。 ## 输入格式 第一行一个正整数 $n$; 第二行 $n$ 个整数,第 $i$ 个整数表示第 $i$ 个结点的父亲的编号,其中第 $1$ 个结点的父亲为 $0$; 第三行 $n$ 个整数,若第 $i$ 个结点没有子结点,则第 $i$ 个数为它的权值,否则第 $i$ 个数为 $p_i\cdot 10000$,保证 $p_i\cdot 10000$ 是个正整数。 ## 输出格式 输出答案。 ## 输入输出样例 #1 ### 输入 #1 ``` 3 0 1 1 5000 1 2 ``` ### 输出 #1 ``` 748683266 ``` ## 说明/提示 #### 样例解释 1号结点的权值有 $\frac{1}{2}$ 的概率是 $1$,有 $\frac{1}{2}$ 的概率是 $2$,所以答案是 $\frac{5}{4}$。 #### 数据范围 - 对于 $10\%$ 的数据,有 $1\leq n\leq 20$; - 对于 $20\%$ 的数据,有 $1\leq n\leq 400$; - 对于 $40\%$ 的数据,有 $1\leq n\leq 5000$; - 对于 $60\%$ 的数据,有 $1\leq n\leq 10^5$; - 另有 $10\%$ 的数据保证树的形态随机; - 对于 $100\%$ 的数据,有 $1\leq n\leq 3\times 10^5$,$1\leq w_i\leq 10^9$。 对于所有数据,满足 $0 < p_i \cdot 10000 < 10000$,所以易证明所有叶子的权值都有概率被根取到。 用C++线段树合并解决
最新发布
09-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值