1. 程式人生 > >BZOJ 2438: [中山市選2011]殺人遊戲 Tarjan

BZOJ 2438: [中山市選2011]殺人遊戲 Tarjan

space inline 認識 ring lag closed 最大 script sizeof

2438: [中山市選2011]殺人遊戲

Description

一位冷血的殺手潛入 Na-wiat,並假裝成平民。警察希望能在 N 個人裏面,查出誰是殺手。警察能夠對每一個人 進行查證,假如查證的對象是平民,他會告訴警察,他認識的人, 誰是殺手, 誰是平民。 假如查證的對象是殺 手, 殺手將會把警察幹掉。現在警察掌握了每一個人認識誰。每一個人都有可能是殺手,可看作他們是殺手的概 率是相同的。問:根據最優的情況,保證警察自身安全並知道誰是殺手的概率最大是多少?

Input

第一行有兩個整數 N,M。
接下來有 M 行,每行兩個整數 x,y,表示 x 認識 y(y 不一定認識 x,例如HJT同誌) 。

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

思路:

  本題的概率沒什麽卵用, 我們發現要求的就是至少要問多少個人才能看到整張圖。縮點, 變成一棵樹 對所有入度為0的進行詢問, 但是有這樣一種情況就是有一個點入度為0, 但是可以問到除了他以外的所有人, 這樣他身份確定就不用問他了,情況需要特判 。

Code :

技術分享圖片
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <stack>
#include <cctype>
#define ms(a) (memset(a, 0, sizeof(a)))
#define min(a, b) (a<b?a:b)
using namespace std;
const int N = 111000, M = 310100;
int head[N], to[M], nxt[M], cnt;
int dfn[N], low[N], place[N], tot; int ins[N], idx; int ind[N]; stack<int>s; int x[M], y[M]; inline char nc() { static char buf[100000], *p1, *p2; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000 ,stdin), p1==p2)?EOF:*p1++; } inline char gc() { char c = nc(); while(isspace(c)) c = nc(); return c; } inline int read() { int x = 0; char c = nc(); while(!isdigit(c))c=nc(); while(isdigit(c)) {x=(x<<3)+(x<<1)+(c^48), c=nc();} return x; } int n=read(), m=read(); void add(int x, int y) { to[++cnt] = y; nxt[cnt] = head[x]; head[x] = cnt; } void Tarjan(int p) { dfn[p] = low[p] = ++idx; s.push(p); ins[p] = 1; for(int i=head[p];i;i=nxt[i]) { if(!dfn[to[i]]) { Tarjan(to[i]); low[p] = min(low[p], low[to[i]]); } else if(ins[to[i]]) { low[p] = min(low[p], dfn[to[i]]); } } if(low[p]==dfn[p]) { tot++; int t = 0; while(t!=p) { t = s.top();s.pop(); ins[t] = 0; place[t] = tot; } } } int rebuild() { int ret = 0; memset(head, 0, sizeof(head)); cnt = 0; for(int i=1;i<=m;i++) { if(place[x[i]]!=place[y[i]]) { add(place[x[i]], place[y[i]]); ind[place[y[i]]] ++; } } for(int i=1;i<=tot;i++) { if(!ind[i]) ret++; } return ret; } bool check(int p) { bool flag = 1; for(int i=head[p];i;i=nxt[i]) { if(ind[to[i]]<=1) flag = 0; } return flag ; } bool hav[N]; int main() { if(n==1) { puts("1.000000"); return 0; } for(int i=1;i<=m;i++) { x[i] = read(), y[i] = read(); add(x[i], y[i]); } int ans = 0, flg = 0; for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); ans = rebuild(); for(int i=1;i<=tot;i++) { if(ind[i]==0&&check(i)) flg = 1; } if(tot==1) ans = 1, flg = 0; printf("%.6lf\n", 1-((ans-flg)*(1.0/n))); }
View Code

BZOJ 2438: [中山市選2011]殺人遊戲 Tarjan