1. 程式人生 > >洛谷 4819 [中山市選]殺人遊戲

洛谷 4819 [中山市選]殺人遊戲

其他 www. tro answer 快的 https www swe sum

題目戳這裏

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;
}

洛谷 4819 [中山市選]殺人遊戲