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

【传送门:BZOJ2438


简要题意:

  有n个人,其中有一个人是杀手,现在作为警察的你要去找到杀手,那么你就要知道每个人的身份

  知道一个人的身份可以直接询问这个人,或者询问认识这个人的人

  如果当前询问的人是杀手,那么你就死了,如果不是,那么这个人会告诉你他认识的所有人的身份

  请问找出杀手并保证自身安全的最大概率


题解:

  一场模拟赛出了这道题,一开始只知道要缩点,但仍不会做

  赛后讲完题才会做

  缩点后,ans=入度为0的连通块个数

  倘若存在只有一个点的连通块,它无入度并且它连向的点均能被其它点到达则ans--


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m;
struct node
{
    int x,y,next;
}a[1110000];int len,last[510000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
struct edge
{
    int x,y,next;
}e[1110000];int len1,last1[510000];
void ins1(int x,int y)
{
    len1++;
    e[len1].x=x;e[len1].y=y;
    e[len1].next=last1[x];last1[x]=len1;
}
int cnt,tp,id;
int belong[510000],dfn[510000],low[510000],sta[510000],size[510000];
bool v[510000];
void dfs(int x)
{
    low[x]=dfn[x]=++id;
    sta[++tp]=x;v[x]=true;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(dfn[y]==-1)
        {
            dfs(y);
            low[x]=min(low[x],low[y]);
        }
        else
        {
            if(v[y]==true) low[x]=min(low[x],dfn[y]);
        }
    }
    if(low[x]==dfn[x])
    {
        int i;cnt++;
        do
        {
            i=sta[tp--];
            v[i]=false;
            belong[i]=cnt;
            size[cnt]++;
        }while(i!=x);
    }
}
int ru[510000],chu[510000],sum1,sum2;
bool check(int x)
{
    if(size[x]!=1)return true;
    if(last1[x]==0)return false;
    for(int k=last1[x];k;k=e[k].next)
    {
        int y=e[k].y;
        if(ru[y]<=1)return true;
    }
    return false;
}
int main()
{
    cnt=tp=id=sum1=sum2=0;
    len=0;len1=0;
    memset(last,0,sizeof(last));memset(last1,0,sizeof(last1));
    scanf("%d%d",&n,&m);
    memset(chu,0,sizeof(chu));
    memset(ru,0,sizeof(ru));
    memset(sta,0,sizeof(sta));
    memset(dfn,-1,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(v,false,sizeof(v));
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y);
    }
    for(int i=1;i<=n;i++) if(dfn[i]==-1) dfs(i);
    for(int i=1;i<=m;i++)
    {
        int st=belong[a[i].x],ed=belong[a[i].y];
        if(st!=ed)
        {
            ru[ed]++;
            ins1(st,ed);
        }
    }
    for(int i=1;i<=cnt;i++) if(ru[i]==0) sum1++;
    for(int i=1;i<=cnt;i++) if(ru[i]==0) if(check(i)==false){sum1--;break;}
    printf("%.6lf\n",1.0-double(sum1)/double(n));
    return 0;
}

 

posted @ 2018-02-12 10:50  Star_Feel  阅读(100)  评论(0编辑  收藏