杀人游戏

问题 C: [中山市选2011]杀人游戏

题目描述

一位冷血的杀手潜入 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 

杀人游戏:

比较难的是怎么想出来如何计算概率:

  警察在搜寻的过程中只有两种结果——找到犯人或死亡,而死亡意味着你找的人是罪犯,因为每个人是罪犯的概率是相等的,所以问题转化为了要调查尽可能少的人来确定所有人的身份,注意到这是一个有向图,所以对那些强连通分量进行tarjan缩点处理,因为只要调查了他们中的一个人,那么就能知道其中所有人的身份,缩点完后在新建的图中是一个森林,我们要找的是那些入度为0的点,结果就是点的数量/总点数,入度不为0那一定能通过其他的点到达这里;

  注意到会有一种特殊情况:如果有一个点没有入度也没有出度(初始时),那么只要调查了其他所有人都不是罪犯,则警察可以不用再去调查他了,他一定罪犯,所以在新图中进行判断,如果入度出度均为0且缩点后点的大小为0且其所能到达的点中只有一个初度,就对点的数量-1/sum就是结果了。

 代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 vector<int>v[100001];
 8 int n,m,x,y,num,cnt,dex;
 9 int adj[100001],in[100001],out[100001];
10 int dfn[100001],low[100001],belong[100001];
11 struct edge{
12     int s,t,next;
13 }k[300001],a[300001];
14 int read(){
15     int sum=0;char ch=getchar();
16     while(ch<‘0‘||ch>‘9‘) ch=getchar();
17     while(ch>=‘0‘&&ch<=‘9‘){sum=sum*10+ch-‘0‘;ch=getchar();}
18     return sum;
19 }
20 void init(int x,int y){
21     k[num].s=x;k[num].t=y;
22     k[num].next=adj[x];adj[x]=num++;
23 }
24 bool t[100001];int zhan[100001],size[100001],head;
25 void tarjan(int x){
26     dfn[x]=low[x]=++dex;
27     t[x]=1;zhan[++head]=x;
28     for(int i=adj[x];i!=-1;i=k[i].next){
29         int o=k[i].t;
30         if(dfn[o]==-1){
31             tarjan(o);
32             low[x]=min(low[x],low[o]);
33         }
34         else
35             if(t[o])
36                 low[x]=min(low[x],dfn[o]);
37     }
38     if(low[x]==dfn[x]){
39         int temp;cnt++;
40         while(1){
41             temp=zhan[head--];
42             belong[temp]=cnt;
43             t[temp]=0;size[cnt]++;
44             if(temp==x)
45                 break;
46         }
47     }
48 }
49 bool search(int x){
50     for(int i=0;i<v[x].size();++i)
51         if(in[v[x][i]]==1)
52             return false;
53     return true;
54 }
55 int main(){
56 //  freopen("killer.in","r",stdin);
57 //  freopen("killer.out","w",stdout);
58     memset(adj,-1,sizeof(adj));
59     memset(dfn,-1,sizeof(dfn));
60     n=read();m=read();
61     for(int i=1;i<=m;++i){
62         x=read();y=read();
63         init(x,y);
64     }
65     for(int i=1;i<=n;++i)
66         if(dfn[i]==-1)
67             tarjan(i);
68     for(int i=0;i<num;++i){
69         if(belong[k[i].t]!=belong[k[i].s]){
70             in[belong[k[i].t]]++;
71             out[belong[k[i].s]]++;
72             v[belong[k[i].s]].push_back(belong[k[i].t]);
73         }
74     }
75     int ans=0;bool flag=false;
76     for(int i=1;i<=cnt;++i){
77         if(!in[i])
78             ans++;
79         if((!in[i]&&!out[i]&&size[i]==1)||(!flag&&!in[i]&&search(i)&&size[i]==1))
80             flag=true;
81     }
82     if(flag) ans--;
83     double res=1-(double)ans/n;
84     printf("%.6lf",res);
85      //while(1);
86     return 0;
87 }
时间: 2024-10-10 05:07:30

杀人游戏的相关文章

[中山市选2011]杀人游戏

[中山市选2011]杀人游戏 时间限制: 1 Sec  内存限制: 128 MB提交: 64  解决: 33[提交][状态][讨论版] 题目描述 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民. 假如查证的对象是杀手, 杀手将会把警察干掉. 现在警察掌握了每一个人认识谁. 每一个人都有可能是杀手,可看作他们是杀手的概率是相同的. 问:根据最优的情况,保

【BZOJ-2438】杀人游戏 Tarjan + 缩点 + 概率

2438: [中山市选2011]杀人游戏 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1638  Solved: 433[Submit][Status][Discuss] Description 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民. 假如查证的对象是杀手, 杀手将会把警察干掉. 现在警察掌

hdu2211杀人游戏

Problem Description 不知道你是否玩过杀人游戏,这里的杀人游戏可没有法官,警察之类的人,只有土匪,现在已知有N个土匪站在一排,每个土匪都有一个编号,从1到N,每次杀人时给定一个K值,从还活着的土匪中,编号从小到大的找到K个人,然后杀掉,继续往下,直到找遍,然后继续从剩下的土匪中,编号从小到大找到第K个活着的土匪,然后杀掉.比如,现在有10个土匪,K为3,第一次杀掉3,6,9号的土匪,第二次杀掉4,8号土匪,第三次杀掉5号土匪,第四次杀掉7号土匪,第五次杀掉10号土匪,我们看到1

BZOJ 2438 杀人游戏(强连通分量)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2438 题意:一位冷血的杀手潜入某村庄,并假装成 平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民. 假如查证的对象是杀手, 杀手将会把警察干掉. 现在警察掌握了每一个人认识谁. 每一个人都有可能是杀手,可看作他们是杀手的概率是相同的. 问:根据最优的情况,保证警察自身 安全并知道谁是杀手

杀人游戏Java代码的实现

前段时间,公司同事问了一个杀人游戏感觉还是挺有意思的,对咱们程序猿来说,只要有规律,一切皆可以用代码来表示(屌丝程序猿的想法). 题目是这样的:有1000名罪犯,对他们进行顺序编号(从1开始).首先,法官要求偶数号的人站出来杀掉.然后在不打乱原有顺序情况下对他们进行顺序编号.再然后法官让奇数号的人站出来杀死.一次类推.问:最后一个人是原先1000人中的几号?(不要问我法官为什么要这样杀人)下面给出个人代码,不吝赐教. int tag = 1;//第几次杀人 int num = 1000;//罪犯

【BZOJ2438】[中山市选2011]杀人游戏 Tarjan

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

hdu 2211 杀人游戏 ~~~应该算是数学问题~~

杀人游戏 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1800    Accepted Submission(s): 405 Problem Description 不知道你是否玩过杀人游戏,这里的杀人游戏可没有法官,警察之类的人,只有土匪,现在已知有N个土匪站在一排,每个土匪都有一个编号,从1到N,每次杀人时给定一个K值,从还活着

hdu 2211 杀人游戏

Problem Description 不 知道你是否玩过杀人游戏,这里的杀人游戏可没有法官,警察之类的人,只有土匪,现在已知有N个土匪站在一排,每个土匪都有一个编号,从1到N,每次杀人时 给定一个K值,从还活着的土匪中,编号从小到大的找到K个人,然后杀掉,继续往下,直到找遍,然后继续从剩下的土匪中,编号从小到大找到第K个活着的土 匪,然后杀掉.比如,现在有10个土匪,K为3,第一次杀掉3,6,9号的土匪,第二次杀掉4,8号土匪,第三次杀掉5号土匪,第四次杀掉7号土匪,第五 次杀掉10号土匪,我

bzoj2438 杀人游戏 Tarjan强联通

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