码迷,mamicode.com
首页 > 其他好文 > 详细

杀人游戏

时间:2018-09-20 01:04:22      阅读:191      评论:0      收藏:0      [点我收藏+]

标签:use   小数   最大   enter   lang   强连通分量   eof   mst   txt   

问题 p: 杀人游戏

时间限制: 1 Sec  内存限制: 128 MB
提交: 3  解决: 2
[提交] [状态] [讨论版] [命题人:admin]

题目描述

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

 

输入

第一行有两个整数 N,M。
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x) 。

 

输出

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

 

样例输入

5 4 
1 2 
1 3 
1 4 
1 5

 

样例输出

0.800000

 

提示

警察只需要查证 1。假如1是杀手,警察就会被杀。假如 1不是杀手,他会告诉警察 2,3,4,5 谁是杀手。而 1 是杀手的概率是 0.2,所以能知道谁是杀手但没被杀的概率是0.8。对于 100%的数据有 1≤N ≤  10 0000,0≤M ≤  30 0000

 Tarjan缩点后求强连通,有x个入度为0的点,则需要调查x次,则最后安全几率为1-x/n。

但这样不完全对,存在一种情况,当警察调查完x-1个人之后,他可以直接确定最后一个人是不是罪犯。这样安全的几率为1-(x-1)/n。而其充分条件为该入度为0的强连通分量,其相连的其他强连通分量入度大于1,。

#include <bits/stdc++.h>
#define  maxn 200000
using namespace std;
int ind[maxn],low[maxn],dfn[maxn],in[maxn],out[maxn],tot,cnt;
bool vis[maxn];
vector<int> a[maxn];
stack<int> s;
struct Edge
{
    int v,next;
};
struct M
{
    int head[maxn];
    Edge edge[maxn*3];
    int cnt;
    void init()
    {
        memset(head,-1, sizeof(head));
        cnt=0;
    }
    void addedge(int u,int v)
    {
        edge[cnt].v=v;
        edge[cnt].next=head[u];
        head[u]=cnt++;
    }
}Mp;
void Tarjan(int num)
{
    vis[num]=true;
    low[num]=dfn[num]=++tot;
    s.push(num);
   for(int i=Mp.head[num];i!=-1;i=Mp.edge[i].next)
   {
       int v=Mp.edge[i].v;
       if(!dfn[v])
       {   Tarjan(v);
           low[num]=min(low[num],low[v]);
       }
       else if(vis[v])
       {
           low[num]=min(low[num],dfn[v]);
       }
   }
   if(dfn[num]==low[num])
   {   ++cnt;
       while(true)
       {
           int now=s.top();
           a[cnt].push_back(now);
           s.pop();
           vis[now]=false;
           ind[now]=cnt;
           if(now==num) break;
       }
   }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int n,m,u,v;
    scanf("%d%d",&n,&m);
    Mp.init();
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        Mp.addedge(u,v);
    }
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i]) Tarjan(i);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=Mp.head[i];j!=-1;j=Mp.edge[j].next)
        {
            int v=Mp.edge[j].v;
            if(ind[v]!=ind[i])
            {
                in[ind[v]]++;
                out[ind[i]]++;
            }
        }
    }
    int sum=0;
    for(int i=1;i<=cnt;i++)
    {
        if(in[i]==0) sum++;
    }
    double ans;
    for(int i=1;i<=cnt;i++)
    {
            if(in[i]==0&&a[i].size()==1)
            {
                int u=a[i][0];
                bool f=false;
                for(int j=Mp.head[u];j!=-1;j=Mp.edge[j].next)
                {
                    int v=Mp.edge[j].v;
                    if(in[ind[v]]<=1) f=true;
                }
                if(f==false)
                {
                    sum--;
                    break;
                }
            }
        }
        ans=1-1.0*sum/n;
        printf("%.6lf\n",ans);
}

  

杀人游戏

标签:use   小数   最大   enter   lang   强连通分量   eof   mst   txt   

原文地址:https://www.cnblogs.com/zyf3855923/p/9678251.html

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