tarjan+概率
杀人游戏
题目描述
一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面查出谁是杀手。
警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民。假如查证的对象是杀手,杀手将会把警察干掉。
现在警察掌握了每一个人认识谁。
每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。
问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少?
输入格式
第一行有两个整数 N,M。
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识x) 。
输出格式
仅包含一行一个实数,保留小数点后面 6 位,表示最大概率。
样例
样例输入1
5 4
1 2
1 3
1 4
1 5
样例输出1
0.800000
样例输入2
4 2
1 2
2 3
样例输出2
0.750000
样例输入3
7 6
4 1
5 4
2 1
7 3
1 6
2 5
样例输出3
0.714286
数据范围与提示
警察只需要查证 1。假如1是杀手,警察就会被杀。假如 1不是杀手,他会告诉警察 2,3,4,5 谁是杀手。而 1 是杀手的概率是 0.2,所以能知道谁是杀手但没被杀的概率是0.8。
对于 100%的数据有 1≤N ≤ 10 0000,0≤M ≤ 30 0000
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int maxn=100000+10,maxm=300000+10; 5 struct Edge{ 6 int to,next,from; 7 }e[maxm<<1]; 8 struct Node{ 9 int to,next; 10 }g[maxm<<1]; 11 int head[maxn],tot=0; 12 void Insert(int a,int b){ 13 e[++tot].to=b; 14 e[tot].from=a; 15 e[tot].next=head[a]; 16 head[a]=tot; 17 } 18 int rhead[maxn],q=0; 19 void add(int a,int b){ 20 g[++q].to=b; 21 g[q].next=rhead[a]; 22 rhead[a]=q; 23 } 24 int dfn[maxn],low[maxn],clock=0,scc[maxn],sc=0,t=0,st[maxn],vis[maxn],size[maxn]; 25 void tarjan(int u){ 26 st[++t]=u; 27 vis[u]=1; 28 low[u]=dfn[u]=++clock; 29 for(int i=head[u];i;i=e[i].next){ 30 int v=e[i].to; 31 if(!dfn[v]){ 32 tarjan(v); 33 low[u]=min(low[u],low[v]); 34 } 35 else if(vis[v]){ 36 low[u]=min(low[u],dfn[v]); 37 } 38 } 39 if(dfn[u]==low[u]){ 40 sc++; 41 while(st[t]!=u){ 42 size[sc]++; 43 scc[st[t]]=sc; 44 vis[st[t]]=0; 45 t--; 46 } 47 size[sc]++; 48 scc[st[t]]=sc; 49 vis[st[t]]=0; 50 t--; 51 } 52 } 53 int main(){ 54 int n,m; 55 scanf("%d%d",&n,&m); 56 for(int i=1;i<=m;i++){ 57 int x,y; 58 scanf("%d%d",&x,&y); 59 Insert(x,y); 60 } 61 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); 62 int flag=0; 63 int rd[maxn]={}; 64 int out[maxn]={}; 65 for(int i=1;i<=m;i++){ 66 int u=e[i].from; 67 int v=e[i].to; 68 if(scc[u]!=scc[v]){ 69 add(scc[u],scc[v]); 70 rd[scc[v]]++; 71 out[scc[u]]++; 72 } 73 } 74 int ans=0; 75 for(int u=1;u<=sc;u++){ 76 if(!rd[u]){ 77 ans++; 78 if(size[u]==1){ 79 int cnt=0; 80 for(int i=rhead[u];i;i=g[i].next){ 81 int v=g[i].to; 82 if(rd[v]<=1) cnt=1; 83 } 84 if(cnt==0) flag=1; 85 } 86 } 87 } 88 double a; 89 if(flag){ 90 a=(double)(ans-1)/n; 91 } 92 else a=(double)ans/n; 93 printf("%.6lf\n",(double)1-a); 94 return 0; 95 }