【bzoj2438】 中山市选2011—杀人游戏

http://www.lydsy.com/JudgeOnline/problem.php?id=2438 (题目链接)

题意

  n个点的有向图,其中有一个是杀手,每个人成为杀手的概率相同。警察询问一个人,如果这个人不是杀手,那么会告诉警察它认识的人哪些是杀手;如果这个人是杀手,警察就挂了。问在最优决策下警察有多大概率找到杀手。

Solution

  熏题。最优决策一定是我们找到一个点,使它能尽可能到达更多的点。然后我们会发现必须询问的人缩点后就是入度为0的点。如果最后剩下了一个人,那么这个人是可以被推出来的,坑死了。

  总的来说,入度为0的点是一定要被询问的,如果存在一个入度为0的点,它的size==1并且到达的所有点的入度>1,这个点是可以被推出来的。

细节

  坑

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// bzoj2438
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define LL long long
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;
 
const int maxn=300010;
int size[maxn],dfn[maxn],low[maxn],bel[maxn],s[maxn],r[maxn];
int head[maxn],u[maxn],v[maxn],num,cnt,top,n,m;
struct edge {int to,next;}e[maxn];
map<pair<int,int>,int> mp;
 
void link(int u,int v) {
    e[++cnt]=(edge){v,head[u]};head[u]=cnt;
}
void Tarjan(int x) {
    dfn[x]=low[x]=++cnt;
    s[++top]=x;
    for (int i=head[x];i;i=e[i].next) {
        if (!dfn[e[i].to]) {
            Tarjan(e[i].to);
            low[x]=min(low[x],low[e[i].to]);
        }
        else if (!bel[e[i].to]) low[x]=min(low[x],dfn[e[i].to]);
    }
    if (low[x]==dfn[x]) {
        bel[x]=++num;size[num]=1;
        while (s[top]!=x) bel[s[top--]]=num,size[num]++;
        top--;
    }
}
int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++) {
        scanf("%d%d",&u[i],&v[i]);
        link(u[i],v[i]);
    }
    cnt=0;
    for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i);
    memset(head,0,sizeof(head));
    for (int i=1;i<=m;i++)
        if (bel[u[i]]!=bel[v[i]] && !mp[pair<int,int>(bel[u[i]],bel[v[i]])]) {
            link(bel[u[i]],bel[v[i]]),r[bel[v[i]]]++;
            mp[pair<int,int>(bel[u[i]],bel[v[i]])]=1;
        }
    int flag=0,ans=0;
    for (int i=1;i<=num;i++) if (!r[i]) {
            ans++;
            int tmp=1;
            for (int j=head[i];j;j=e[j].next) if (r[e[j].to]==1) {tmp=0;break;}
            flag|=tmp & (size[i]==1);
        }
    printf("%.6lf",(double)(n-ans+flag)/n);
    return 0;
}

 

posted @   MashiroSky  阅读(266)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示