zoukankan      html  css  js  c++  java
  • bzoj 2438 [中山市选2011]杀人游戏(SCC+概率)

    【题目链接】

        http://www.lydsy.com/JudgeOnline/problem.php?id=2438

    【题意】

        N个人中有一个杀手,每次询问一个人可能被杀或被告知其认识的人中谁是杀手谁是平民,问不被杀的情况下知道谁是杀手的概率。

    【思路】

        对于一个scc,如果我们询问一个不是杀手的人,就可以成功遍历整个scc。

        求scc,然后缩点。

        对于每一个入度为0的scc,我们需要去询问一下,那么被杀的概率为1/n * ans。ans为入度为0的scc个数。

        但还有一种特殊的情况,如果一个scc入度为0,但它的所有出度的入度皆大于1,那么它的出度可以不通过询问这个scc得知,而且最终通过其他n-1个点推出这个点的情况。这时候需要对ans-1,但这种情况只计算一次。

    【代码】

     1 #include<set>
     2 #include<cmath>
     3 #include<queue>
     4 #include<vector>
     5 #include<cstdio>
     6 #include<cstring>
     7 #include<iostream>
     8 #include<algorithm>
     9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
    10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
    11 using namespace std;
    12 
    13 typedef long long ll;
    14 const int N = 2e5+10;
    15 const int M = 7e5+10;
    16 
    17 ll read() {
    18     char c=getchar();
    19     ll f=1,x=0;
    20     while(!isdigit(c)) {
    21         if(c=='-') f=-1; c=getchar();
    22     }
    23     while(isdigit(c))
    24         x=x*10+c-'0',c=getchar();
    25     return x*f;
    26 }
    27 
    28 struct Edge {
    29     int v,nxt;
    30 }e[M];
    31 int en=1,front[N];
    32 void adde(int u,int v)
    33 {
    34     e[++en]=(Edge){v,front[u]}; front[u]=en;
    35 }
    36 
    37 int pre[N],lowlink[N],scc_cnt,sccno[N],S[N],top,dfn;
    38 
    39 void tarjan(int u)
    40 {
    41     pre[u]=lowlink[u]=++dfn;
    42     S[++top]=u;
    43     trav(u,i) {
    44         int v=e[i].v;
    45         if(!pre[v]) {
    46             tarjan(v);
    47             lowlink[u]=min(lowlink[v],lowlink[u]);
    48         } else
    49         if(!sccno[v])
    50             lowlink[u]=min(lowlink[u],pre[v]);
    51     }
    52     if(pre[u]==lowlink[u]) {
    53         ++scc_cnt;
    54         for(;;) {
    55             int x=S[top--];
    56             sccno[x]=scc_cnt;
    57             if(x==u) break;
    58         }
    59     }
    60 }
    61 
    62 int cnt[N],in[N],n,m,ans;
    63 
    64 int main()
    65 {
    66     n=read(),m=read();
    67     int u,v;
    68     FOR(i,1,m) {
    69         u=read(),v=read();
    70         adde(u,v);
    71     }
    72     FOR(i,1,n) if(!pre[i]) tarjan(i);
    73     FOR(u,1,n) {
    74         cnt[sccno[u]]++;
    75         trav(u,i) {
    76             int v=e[i].v;
    77             if(sccno[u]!=sccno[v]) 
    78                 in[sccno[v]]++;
    79         }
    80     }
    81     FOR(i,1,scc_cnt) if(!in[i]) ans++;
    82     int flag=0;
    83     FOR(i,1,n) 
    84         if(cnt[sccno[i]]==1&&in[sccno[i]]==0) {
    85             int f=1;
    86             trav(i,j) {
    87                 int v=e[j].v;
    88                 if(in[sccno[v]]<=1) { f=0; break; } 
    89             }
    90             if(f) {
    91                 flag=1; break;
    92             }
    93         }
    94     ans-=flag;
    95     printf("%.6lf
    ",(double)(n-ans)/n);
    96     return 0;
    97 }
  • 相关阅读:
    linux常用统计命令
    linux文件处理命令
    linux三剑客和管道使用
    bash编程语法
    第八章:用通配符进行过滤
    第七章:数据过滤
    第六章:过滤数据
    第五章:排序检索数据
    第四章:检索数据
    第二章:MYSQL简介
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5335771.html
Copyright © 2011-2022 走看看