bzoj2438 [中山市选2011]杀人游戏 强连通分量缩点

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/82624454

Description


一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,查出谁是杀手。警察能够对每一个人
进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民。 假如查证的对象是杀
手, 杀手将会把警察干掉。现在警察掌握了每一个人认识谁。每一个人都有可能是杀手,可看作他们是杀手的概
率是相同的。问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少?

对于 100%的数据有 1≤N ≤ 10 0000,0≤M ≤ 30 0000

Solution


注意到给出的是有向边,若图为DAG显然我们选择拓扑序更小的点更优秀,放在有向图上就是选择缩点后入度为0的强连通分量最优秀
需要注意的是,对于像3 0这样的数据答案为0.333333,也即是我们可以通过排除法问完n-1个人后剩下的人身份就确定了,这个需要特判一下

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stack>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))

const int N=100005;

struct Graph {
    struct edge {int x,y,next;} e[N*3];

    int ls[N],edCnt;

    void add_edge(int x,int y) {
        e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
    }
} E,G;

std:: stack <int> stack;

int dfn[N],low[N],scc[N],ind[N],size[N];

bool vis[N],flag;

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void dfs(int now) {
    dfn[now]=low[now]=++dfn[0];
    vis[now]=true; stack.push(now);
    for (int i=E.ls[now];i;i=E.e[i].next) {
        if (!dfn[E.e[i].y]) {
            dfs(E.e[i].y); low[now]=std:: min(low[now],low[E.e[i].y]);
        } else if (vis[E.e[i].y]) {
            low[now]=std:: min(low[now],dfn[E.e[i].y]);
        }
    }
    if (low[now]==dfn[now]) {
        int y=0; scc[0]++;
        while (y!=now) {
            y=stack.top(); stack.pop();
            scc[y]=scc[0]; vis[y]=0; size[scc[0]]++;
        }
    }
}

bool check(int x) {
    if (flag) return false;
    if (size[x]!=1) return false;
    for (int i=G.ls[x];i;i=G.e[i].next) {
        if (ind[G.e[i].y]==1) return false;
    }
    return flag=true;
}

int main(void) {
    int n=read(),m=read();
    rep(i,1,m) {
        int x=read(),y=read();
        E.add_edge(x,y);
    }
    rep(i,1,n) if (!dfn[i]) dfs(i);
    rep(i,1,E.edCnt) {
        if (scc[E.e[i].x]!=scc[E.e[i].y]) {
            G.add_edge(scc[E.e[i].x],scc[E.e[i].y]);
            ind[scc[E.e[i].y]]++;
        }
    }
    int ans=0;
    rep(i,1,scc[0]) if (!ind[i]) {
        if (check(i)) continue;
        ans++;
    }
    printf("%.6lf\n", 1.0*(n-ans)/n);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/82624454