【算法】Tarjan大锦集

Task1

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

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

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#define il inline
using namespace std;
const int N=1000001;
struct edge{int next,to;} e[N];
int n,M,m,scc,g[N],dfn[N],low[N],ins[N],s[N],bel[N],hav[N],ans,d[N],ind,top;
il void addedge(int x,int y){
    e[++M]=(edge){g[x],y};g[x]=M;d[y]++;
}
il void tarjan(int h){
    dfn[h]=low[h]=(++ind);
    ins[h]=1;s[++top]=h;
    for(int i=g[h];i;i=e[i].next)
        if(!dfn[e[i].to]){
            tarjan(e[i].to);
            low[h]=min(low[h],low[e[i].to]);
        }
        else if(ins[e[i].to])
            low[h]=min(low[h],dfn[e[i].to]);
    if(low[h]==dfn[h]){
        int now=0;scc++;
        while(h!=now){
            now=s[top--];
            bel[now]=scc;
            hav[scc]++;
            ins[now]=0;
        }
    }
}
il void rebuild(){
    for(int i=1;i<=n;i++){
        for(int j=g[i];j;j=e[j].next){
            if(bel[i]!=bel[e[j].to]){
                addedge(bel[i]+n,bel[e[j].to]+n);
            }
        }
    }
}
il bool chk(int h){
    if(d[h]!=0||hav[h-n]!=1) return 0;
    for(int i=g[h];i;i=e[i].next){
        if(d[e[i].to]==1) return 0;
    }
    return 1;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1,x,y;i<=m;i++){
        scanf("%d%d",&x,&y);
        addedge(x,y);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    rebuild();
    for(int i=1;i<=scc;i++)
        if(d[i+n]==0) ans++; 
    for(int i=1;i<=scc;i++) 
        if(chk(i+n)){
            ans--;break;
        }
    printf("%.6lf",double(n-ans)/n);
    return 0;
}

 


posted @ 2016-11-18 11:46  ExiledPoet  阅读(154)  评论(0编辑  收藏  举报