BZOJ——2438: [中山市选2011]杀人游戏
http://www.lydsy.com/JudgeOnline/problem.php?id=2438
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
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
数据已加强!
Source
杀手与村民为对立事件,警察存活概率=1-p(被杀), p(被杀)=可能为杀手的人数/n
因为警察根据最优情况选人,那么求出scc,警察第一个人会选择入度为零的scc,算出这些scc成为杀手的概率即可
(一个scc成为杀手的概率为 1/n ,因为在一个scc中问一个人就可以知道此块中的所有信息)
特别的:如果存在一个独立的scc(可以根据访问别的人判断此块信息,即该块只有一个人,连出去的点的入读>1),
则该scc不需要统计,因为可以通过别的推断出,即 cnt--
1 #include <cstdio> 2 3 #define min(a,b) (a<b?a:b) 4 5 inline void read(int &x) 6 { 7 x=0; register char ch=getchar(); 8 for(; ch>'9'||ch<'0'; ) ch=getchar(); 9 for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; 10 } 11 12 const int N(100005); 13 const int M(300005); 14 15 int n,m,sumedge,cnt; 16 int head[N],_v[M<<1],_nex[M<<1]; 17 18 inline void ins(int u,int v) 19 { 20 _v[++sumedge]=v; 21 _nex[sumedge]=head[u]; 22 head[u]=sumedge; 23 } 24 25 int tim,dfn[N],low[N],rd[N]; 26 int top,Stack[N],instack[N]; 27 int sumcol,col[N],point[N]; 28 29 void DFS(int u) 30 { 31 dfn[u]=low[u]= ++tim; 32 Stack[++top]=u; instack[u]=1; 33 for(int i=head[u]; i; i=_nex[i]) 34 { 35 if(!dfn[_v[i]]) DFS(_v[i]),low[u]=min(low[u],low[_v[i]]); 36 else if(instack[_v[i]]) low[u]=min(low[u],dfn[_v[i]]); 37 } 38 if(low[u]!=dfn[u]) return ; 39 point[col[u]= ++sumcol] ++; 40 for(; Stack[top]!=u; --top) 41 { 42 point[sumcol]++; 43 instack[Stack[top]]=0; 44 col[Stack[top]]=sumcol; 45 } 46 instack[u]=0, --top; 47 } 48 49 int Presist() 50 { 51 read(n),read(m); 52 for(int u,v,i=1; i<=m; ++i) 53 read(u),read(v),ins(u,v); 54 for(int i=1; i<=n; ++i) 55 if(!dfn[i]) DFS(i); 56 for(int u=1; u<=n; ++u) 57 for(int i=head[u]; i; i=_nex[i]) 58 if(col[u]!=col[_v[i]]) rd[col[_v[i]]]++; 59 for(int i=1; i<=sumcol; ++i) cnt+=(!rd[i]); 60 for(int u=1; u<=n; ++u) 61 { 62 if(rd[col[u]]||point[col[u]]>1) continue; 63 for(int i=head[u]; i; i=_nex[i]) 64 if(rd[col[_v[i]]]<2) goto next_; 65 cnt--; break; next_:; 66 } 67 printf("%.6lf\n",1*1.-1.*cnt/n); 68 return 0; 69 } 70 71 int Aptal=Presist(); 72 int main(int argc,char**argv){;}
——每当你想要放弃的时候,就想想是为了什么才一路坚持到现在。