洛谷 4819 [中山市选]杀人游戏

题目戳这里
Solution

首先我们可以想到,如果某个人没有任何一个人认识他,那么警察必须通过调查他获取他的身份,那么思路便很清晰了,从所有入度为0的点遍历,就可以获得所有人的身份,并且易知这样的花费也是最少的,但如果这张图就是一个环呢?那么不是没有一个入度为0的点?所以我们需要通过缩点来使这张图变成DAG,记录所有入度为0的点除以总点数。
然后...你就会发现只有21分,233。
为什么呢?举个栗子:
假设你通过其他的点把整张图遍历完了,只剩下一个点,那么我们还需要对他遍历吗?因为只有一个杀手,所以很明显通过其他人的身份就知道这个人的身份,所以这种情况需要特判。
但这个点满足什么条件呢?很明显不需要它也可以把其他点遍历完,要么是他不连接任何点,要么是它连接的点度数都大于1(通过其他点也可以到达)。这样就可以愉快的AC了!
PS:数组真的要开大点,很坑!!!

Coding

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
struct road
{
    int to,next;
}e[N*5],edge[N*5];
int n,m,head[N],cnt,u[N],v[N],in[N];
void add(int x,int y)
{
    e[++cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt;
}
void Readd(int x,int y)
{
    edge[++cnt].to=y;
    edge[cnt].next=head[x];
    head[x]=cnt;
}
int sum,color[N],low[N],ins[N],Time[N],sta[N],top=1,col,num[N];
void Tarjan(int x)
{
    Time[x]=low[x]=++sum;
    sta[top++]=x;
    ins[x]=1;
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(ins[v]==0)
        {
            Tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(ins[v]==1) low[x]=min(low[x],Time[v]);
    }
    if(Time[x]==low[x])
    {
        col++;
        do
        {
            top--;
            color[sta[top]]=col;
            ins[sta[top]]=-1;
        }while(sta[top]!=x);
    }
    return ;
}
int main()
{
    cin>>n>>m;
    if(n==1) {cout<<"1.000000"; return 0;}
    if(m==0) {printf("%.6lf",1.0/n); return 0;}
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u[i],&v[i]);
        add(u[i],v[i]);
    }
    for(int i=1;i<=n;i++)
    if(!ins[i]) Tarjan(i);
    memset(head,0,sizeof(head));
    cnt=0;
    for(int i=1;i<=n;i++)
        num[color[i]]++;
    for(int i=1;i<=m;i++)
        if(color[u[i]]!=color[v[i]]) Readd(color[u[i]],color[v[i]]),in[color[v[i]]]++;
    int flag=0,ans=0;
    for(int x=1;x<=col;x++)
    {
        int fuck=1;
        if(in[x]!=0) continue ;
        if(num[x]!=1) continue ;
        for(int i=head[x];i;i=edge[i].next)
            if(in[edge[i].to]==1) {fuck=0; break ;}
        if(fuck==1)
        {
            flag=1;
            break ;
        }
    }
    for(int i=1;i<=col;i++)
    if(in[i]==0) ans++;
    ans-=flag;
    double answer=double(n-ans)/double(n);
    printf("%.6lf",answer);
    return 0;
}
posted @ 2018-09-04 15:09  Le_Mon  阅读(189)  评论(0编辑  收藏  举报