bzoj2438[中山市选2011]杀人游戏

Description

一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,
查出谁是杀手。
警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他
认识的人, 谁是杀手, 谁是平民。 假如查证的对象是杀手, 杀手将会把警察干掉。
现在警察掌握了每一个人认识谁。
每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。
问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多
少?

Input

第一行有两个整数 N,M。
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x,例如胡锦涛同志) 。

Output

仅包含一行一个实数,保留小数点后面 6 位,表示最大概率。

Sample Input

5 4
1 2
1 3
1 4
1 5

Sample Output

0.800000

HINT

警察只需要查证 1。假如1是杀手,警察就会被杀。假如 1不是杀手,他会告诉警

察 2,3,4,5 谁是杀手。而 1 是杀手的概率是 0.2,所以能知道谁是杀手但没被杀的概

率是0.8。对于 100%的数据有 1≤N ≤  10 0000,0≤M ≤  30 0000


数据已加强!

思路:本人初中党表示对概率这东西不是很懂。。。

大神的题解:http://www.cnblogs.com/xkui/p/4552391.html

题目的关键在于要想到,既然是关系问题(思考一下并查集是否可以解?不能,我认为出现了“x 认识 y(y 不一定认识 x,例如胡锦涛同志)”表明不可用),就涉及到只要是几个人构成了有向图强联通分量,那么质问其中一人就可以得知所有的分量内的关系,缩一下点就没有必要枚举所有人。而此时,直接去问那些入度为0的分量。至于为什么可以参照这个公式哦:

ans=(n-1)/n(第一次问不是罪犯)*[(s1-1/n-1)(集合在第一点集中)+((n-s1)/(n-1))*((n-s1-1)/(n-s1))*((s2-1)*(n-s1-1))(分别为,不在第一点集,第二次不问到罪犯,在第二点集的概率)+...]。(问入度为0的点集可以保证它们之间互补相干)。

当然此题程序也并非单纯的模板

特判:当有一个分量只包括一个点、入度为0且不影响其他分量的入度是否为0(似乎不是桥),那么当其他点问过后,就不用关心这个点了,从ans中删除它的增量1。

1590224

  ksq2013 2438 Accepted 37256 kb 1032 ms C++/Edit 2083 B 2016-08-14 11:08:14

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,first[1000111],du[1000111],sz[1000111],hd[1000111],ecnt,ans=0;
int pre[1000111],sccn[1000111],lowlink[1000111],mstack[1000111],stack_cnt,dfs_clock,scc_cnt;
struct edge{
    int u,v,nxt;
}e[300333];
void link(int u,int v)
{
    e[++ecnt].u=u;
    e[ecnt].v=v;
    e[ecnt].nxt=first[u];
    first[u]=ecnt;
}
void dfs(int u)
{
    int v;
    pre[u]=lowlink[u]=++dfs_clock;
    mstack[++stack_cnt]=u;
    for(int i=first[u];i;i=e[i].nxt){
        v=e[i].v;
        if(!pre[v]){
            dfs(v);
            lowlink[u]=min(lowlink[u],lowlink[v]);
        }
        else if(!sccn[v])
            lowlink[u]=min(lowlink[u],pre[v]);
    }
    if(!(pre[u]^lowlink[u])){
        hd[++scc_cnt]=u;
        do{
            v=mstack[stack_cnt--];
            sccn[v]=scc_cnt;
            ++sz[scc_cnt];
        }while(v^u);
    }
}
void tarjan()
{
    memset(pre,0,sizeof(pre));
    memset(sccn,0,sizeof(sccn));
    memset(lowlink,0,sizeof(lowlink));
    stack_cnt=dfs_clock=scc_cnt=0;
    for(int i=1;i<=n;i++)
        if(!pre[i])
            dfs(i);
}
bool jud(int u)
{
    for(int i=first[u];i;i=e[i].nxt)
        if(du[sccn[e[i].v]]==1)
            return 0;
    return 1;
}
int main()
{
    memset(sz,0,sizeof(sz));
    memset(du,0,sizeof(du));
    memset(first,0,sizeof(first));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        link(u,v);
    }
    tarjan();
    for(int i=1;i<=ecnt;i++)
        if(sccn[e[i].u]^sccn[e[i].v])
            ++du[sccn[e[i].v]];
    for(int i=1;i<=scc_cnt;i++)
        if(!du[i])
            ++ans;
    for(int i=1;i<=scc_cnt;i++)//special judge;
        if(!du[i]&&sz[i]==1&&jud(hd[i]))
            {--ans;break;}
    printf("%.6lf\n",(double)(n-ans)/n);
    return 0;
}


posted @ 2016-08-14 11:28  keshuqi  阅读(101)  评论(0编辑  收藏