BZOJ 2438: [中山市选2011]杀人游戏 Tarjan

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

 

posted @ 2018-06-26 19:39  TOBICHI_ORIGAMI  阅读(72)  评论(0编辑  收藏