zoukankan      html  css  js  c++  java
  • 【luogu4819】 [中山市选]杀人游戏 [tarjan 缩点]

    P4819 [中山市选]杀人游戏

    显然问的人越少越好,若问了k个人,答案为(n-k)/n
    若点x有入边,询问x的前驱比询问x要好;但如果有环,区分有没有从环外指向环内的边,若有进入环的边,……,若没有,……,所以可以先缩点
    缩环之后图会变成拓扑图,只需要每个入度为0的点进行一次询问即可得知凶手,所以答案为(n-入度为0的点)/n
    需要注意的是如果存在某个入度为0的点,其儿子块可由别的询问确定,可以少询问一次……增加1/n的概率
    #include<bits/stdc++.h>
    using namespace std;
    #define Max(x,y) (x)>(y)?(x):(y)
    #define Min(x,y) (x)>(y)?(y):(x)
    #define ll long long
    #define rg register
    const int N=1000000+5,M=10000+5,inf=0x3f3f3f3f,P=99999997;
    map<string,int>a;
    int n,m,ans=0,in[N];
    int dfn[N],low[N],bl[N],size[N],Bcnt=0,idx=0;
    bool inst[N];
    stack<int>s;
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    int head[N],tot=0;
    struct edge{int u,v,nxt;}e[N<<1];
    void add(int u,int v){
        e[++tot]=(edge){u,v,head[u]},head[u]=tot;
    }
    
    void tarjan(int u){
        dfn[u]=low[u]=++idx;
        s.push(u),inst[u]=1;
        for(int i=head[u],v;i;i=e[i].nxt){
            v=e[i].v;
            if(!dfn[v]) tarjan(v),low[u]=Min(low[u],low[v]);
            else if(inst[v]&&dfn[v]<low[u]) low[u]=dfn[v];
        }
        if(low[u]==dfn[u]){
            int v;++Bcnt;
            do{
                v=s.top(),s.pop();
                bl[v]=Bcnt,inst[v]=0,++size[Bcnt];
            }while(v!=u);
        }
    }
    
    int main(){
    //    freopen("in.txt","r",stdin);
        rd(n),rd(m);
        for(int i=1,u,v;i<=m;++i)
        rd(u),rd(v),add(u,v);
        for(int i=1;i<=n;++i)
        if(!dfn[i]) tarjan(i);
        memset(head,0,sizeof(head));tot=0;
        for(int i=1;i<=m;++i)
        if(bl[e[i].u]!=bl[e[i].v])
        ++in[bl[e[i].v]],add(bl[e[i].u],bl[e[i].v]);
        int flag=0;
    //    for(int i=1;i<=Bcnt;++i)printf("%d,%d ",in[i],size[i]);
        for(int i=1;i<=Bcnt;++i){
            if(!flag&&!in[i]&&size[i]==1){
                int fl=0;
                for(int j=head[i];j;j=e[j].nxt)
                if(in[e[j].v]==1) fl=1;
                if(!fl) flag=1;
            }
            if(!in[i]) ++ans;
        }
        if(flag) --ans;
    //    printf("%d %d",flag,ans);
        printf("%.6f",(double)(n-ans)/n);
        return 0;
    }
     
  • 相关阅读:
    page1
    CodeForces
    树、递归————二叉树的所有路径
    树(未完)
    树、递归、遍历————二叉搜索树的最近公共祖先
    树、递归————翻转二叉树
    树、递归————路径总和
    树、递归、广度优先搜索(BFS)————二叉树的最小深度
    树————平衡二叉树
    平衡二叉树AVL
  • 原文地址:https://www.cnblogs.com/lxyyyy/p/11228050.html
Copyright © 2011-2022 走看看