今天的木留又在打摆子QAQ但是木留还是要努力变强ovo

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

2438: [中山市选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


刚刚接触tarjan算法……说是之后某神犇会出tarjan的题orz写思路前一定要多说一句QAQ写tarjan函数的时候,

for (int i=head[x];i;i=e[i].next)
    {
        int y=e[i].v;
        if (!dfn[y])
        {
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if (vis[y])
        {
            low[x]=min(dfn[y],low[x]);
        }
    }

这个千万要注意……查了一个晚上一个中午的错orz好气。vis记录的是是否在栈中,而不是是否遍历过,所以要用dfn来判断,所以当vis为0时此点其实可能已经搜过了……

最开始看到概率就很懵逼,样例也比较水,就翻了dalao的题解看了下解释……

因为询问一个人只有两种可能,一种此人是杀手,一种此人不是。所以概率即为:(1-询问人数/总人数)

那么要求最大概率,就要使询问人数最少。这个时候思路就很明显了,先tarjan缩点,然后求出入度为0的点的个数(必须要询问)。

这个时候还有一种特殊情况,某个入度为0的点,它所连向的所有点得入度都>1,即我们确实是不需要询问这个点就可以知道答案的。所以就减去即可。

代码如下ovo

  1     #include<iostream>  
  2     #include<cstdio>  
  3     #include<cstdlib>  
  4     #include<cstring>  
  5     #include<string>  
  6     #include<cmath>  
  7     #include<algorithm>  
  8     #include<queue>  
  9     using namespace std;  
 10     int read()  
 11     {  
 12         int f=1,p=0;  
 13         char c=getchar();  
 14         while (c<'0'||c>'9') {if (c=='-')  f=-1;c=getchar();}  
 15         while (c>='0'&&c<='9') {p=p*10+c-'0';c=getchar();}  
 16         return f*p;  
 17     }  
 18     struct edge  
 19     {  
 20         int next,u,v;  
 21     }e[300005],nw[300005];  
 22     int tot=0,s=0,n,m,sum=0,res=0.0;  
 23     int st[300005],vis[100005],num[300005],be[300005],head[300005],enter[300005],hd[300005],low[100005],dfn[100005];  
 24     void tarjan(int x)  
 25     {  
 26         low[x]=dfn[x]=++tot;  
 27         vis[x]=1;  
 28         st[++s]=x;  
 29         for (int i=head[x];i;i=e[i].next)  
 30         {  
 31             int y=e[i].v;  
 32             if (!dfn[y])  
 33             {  
 34                 tarjan(y);  
 35                 low[x]=min(low[x],low[y]);  
 36             }  
 37             else if (vis[y])  
 38             {  
 39                 low[x]=min(dfn[y],low[x]);  
 40             }  
 41         }  
 42         if (low[x]==dfn[x])  
 43         {  
 44             while (st[s+1]!=x)  
 45             {  
 46                 num[x]++;  
 47                 be[st[s]]=x;  
 48                 vis[st[s]]=0;  
 49                 s--;  
 50             }  
 51         }  
 52     }  
 53     int main()  
 54     {  
 55         n=read();m=read();  
 56         for (int i=1;i<=m;i++)  
 57         {  
 58             int u=read(),v=read();  
 59             e[i].u=u;  
 60             e[i].v=v;  
 61             e[i].next=head[u];  
 62             head[u]=i;  
 63         }  
 64         for (int i=1;i<=n;i++)  
 65         {  
 66             if (!dfn[i]) tarjan(i);  
 67         }  
 68         for (int i=1;i<=n;i++)  
 69         {  
 70             for (int j=head[i];j;j=e[j].next)  
 71             if (be[i]!=be[e[j].v])  
 72             {  
 73                 ++sum;  
 74                 nw[sum].u=be[i];  
 75                 nw[sum].v=be[e[j].v];  
 76                 nw[sum].next=hd[be[i]];  
 77                 hd[be[i]]=sum;  
 78                 ++enter[be[e[j].v]];  
 79             }  
 80         }  
 81         for (int i=1;i<=n;i++)  
 82         {  
 83             if (!vis[be[i]]&&!enter[be[i]])  
 84             {  
 85                 vis[be[i]]=1;  
 86                 res++;  
 87             }  
 88         }  
 89         for (int i=1;i<=n;i++)  
 90         {  
 91             if (num[be[i]]==1&&vis[be[i]])  
 92             {  
 93                 int flag=0;  
 94                 for (int j=hd[be[i]];j;j=nw[j].next)  
 95                 if (enter[nw[j].v]<=1) {flag=1;break;}  
 96                 if (!flag) {res--;break;}  
 97             }  
 98         }  
 99         double ans=(double)(1.0-(double)(1.0*res/n));  
100         printf("%.6lf",ans);  
101         return 0;  
102     }  

 

posted @ 2017-02-14 17:05  木留木留木  阅读(223)  评论(0编辑  收藏