BZOJ 2438 中山市选2011 杀人游戏

Posted zhangenming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2438 中山市选2011 杀人游戏相关的知识,希望对你有一定的参考价值。

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

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2815  Solved: 808
[Submit][Status][Discuss]

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


数据已加强! 

Source

容斥一下,最优的的方式就是去询问那些入度为0的点

那种情况是我们按照这种方式完不成任务的呢,就是入度为0的店是杀手

那么我们先对图进行Tarjan缩一下点,有入度的点,显然我们可以不用直接访问,那么我们访问每个入度为0的点

不过这里有个特殊情况,如果存在一个被搁置的点,他最后是不用访问的比如:3个人ABC,A认识B,那么访问A后,A,B和C的身份都能得知

这样就可以少询问一个,但是注意,这种情况的条件是:

入度为0,且只包含1个点,且这个点指向的SCC的入度>=2(缩点前)【并不仅仅是出入度为0】<-特别容易出错

比如:3个人ABC,A认识B,C认识B,那么访问A或C后都可以得到所有人身份;

技术分享图片
 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 inline int read(){
 5     int x=0;int f=1;char ch=getchar();
 6     while(!isdigit(ch)) {if(ch==-) f=-1;ch=getchar();}
 7     while(isdigit(ch)) {x=x*10+ch-0;ch=getchar();}
 8     return x*f;
 9 }
10 const int MAXN=1e6+10;
11 struct node{
12     int y,next;
13 }e[MAXN],E[MAXN];
14 int linkk[MAXN],Linkk[MAXN],len,stark[MAXN],n,m,cnt[MAXN],sum[MAXN],dfs_clock=0,top,mark[MAXN],ine[MAXN],tot,vis[MAXN],dfn[MAXN],low[MAXN];
15 inline void insert(int xx,int yy){
16     e[++len].y=yy;e[len].next=linkk[xx];linkk[xx]=len;
17 }
18 inline void insertt(int xx,int yy){
19     E[++len].y=yy;E[len].next=Linkk[xx];Linkk[xx]=len;
20 }
21 inline void tarjin(int st){
22     dfn[st]=low[st]=++dfs_clock;
23     vis[st]=1;stark[++top]=st;
24     for(int i=linkk[st];i;i=e[i].next){
25         if(!dfn[e[i].y]){
26             tarjin(e[i].y);
27             low[st]=min(low[e[i].y],low[st]);
28         }
29         else if(vis[e[i].y]) low[st]=min(low[st],dfn[e[i].y]);
30     }
31     if(dfn[st]==low[st]){
32         int k;tot++;
33         do{
34             k=stark[top--];
35             vis[k]=0;
36             ine[k]=tot;
37             sum[tot]++;
38         }while(k!=st);
39     }
40 }
41 void init(){
42     n=read();m=read();
43     for(int i=1;i<=m;i++){
44         int xx=read();int yy=read();
45         insert(xx,yy);
46     }
47 }
48 void rebuild(){
49     len=0;
50     for(int i=1;i<=n;i++){
51         for(int j=linkk[i];j;j=e[j].next){
52             if(ine[i]!=ine[e[j].y]&&!mark[ine[e[j].y]]){
53                cnt[ine[e[j].y]]++;mark[ine[e[j].y]]=1;
54                //cout<<ine[i]<<‘ ‘<<ine[e[j].y]<<endl;
55                insertt(ine[i],ine[e[j].y]);
56             }
57         }
58         for(int j=linkk[i];j;j=e[j].next){
59             mark[ine[e[j].y]]=0;
60         }
61     }
62 }
63 inline bool dp(int st){
64     if(cnt[st]!=0||sum[st]!=1) return 0;
65     for(int i=Linkk[st];i;i=E[i].next){
66         if(cnt[E[i].y]==1) return 0;
67     }
68     return 1;
69 }
70 void solve(){
71     for(int i=1;i<=n;i++){
72         if(!dfn[i]) tarjin(i);
73     }
74     rebuild();
75     int ans=0;
76     for(int i=1;i<=tot;i++){
77         if(!cnt[i]){
78             ans++;
79         }
80     }
81     for(int i=1;i<=tot;i++){
82         if(dp(i)){
83             ans--;break;
84         }
85     }
86     printf("%lf\n",1.0*(n-ans)/n);
87 }
88 int main(){
89     init();
90     solve();
91     return 0;
92 }
View Code

 













以上是关于BZOJ 2438 中山市选2011 杀人游戏的主要内容,如果未能解决你的问题,请参考以下文章

bzoj2438: [中山市选2011]杀人游戏(强联通+特判)

bzoj 2438 [中山市选2011]杀人游戏(SCC+概率)

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

BZOJ2438: [中山市选2011]杀人游戏

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

bzoj 2438: [中山市选2011]杀人游戏tarjan