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

题意

题目链接

Sol

这题挺考验阅读理解能力的。。

如果能读懂的话,不难发现这就是在统计有多少入度为\(0\)的点

缩点后判断一下即可

当然有一种例外情况是\(1 -> 3, 2 -> 3\),也就是存在一个孤立点,判掉即可

判断的时候应当满足三个条件:所在联通块大小为\(2\),入度为0,所有指向的点入度均大于\(2\)

另外就是题目中没有说有没有重边,我没判过了,但是最好还是判一下。

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 10;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N, M;
vector<int> v[MAXN];//let's have a test
int dfn[MAXN], low[MAXN], vis[MAXN], tot, col[MAXN], cn, inder[MAXN], ans, siz[MAXN], flag[MAXN];
stack<int> s;
void tarjan(int x) {
    dfn[x] = low[x] = ++tot; vis[x] = 1; s.push(x);
    vector<int> *e = &v[x];
    for(int i = 0, to; i < e -> size(); i++) {
        if(!dfn[to = (*e)[i]]) tarjan(to), low[x] = min(low[x], low[to]);
        else if(vis[to]) low[x] = min(low[x], dfn[to]);
    }
    if(low[x] == dfn[x]) {
        int h; ++cn;
        do {
            h = s.top(); s.pop(); vis[h] = 0; col[h] = cn; siz[cn]++;
        }while(h != x);
    }
}
void rebuild() {
    for(int i = 1; i <= N; i++) {
        vector<int> *e = &v[i];
        for(int j = 0, to; j < e -> size(); j++) 
            if(col[i] != col[to = (*e)[j]]) 
                inder[col[to]]++;		
    } 
    for(int i = 1; i <= cn; i++) if(!inder[i]) ans++;
}
int main() {
    N = read(); M = read();
    for(int i = 1; i <= M; i++) {
        int x = read(), y = read();
        v[x].push_back(y);
    }
    for(int i = 1; i <= N; i++) if(!dfn[i]) tarjan(i);
    rebuild();
    for(int i = 1; i <= N; i++) {
        if((!inder[col[i]]) && siz[col[i]] == 1) {
            bool flag = 0; vector<int> *e = &v[i];
            for(int j = 0, to; j < e -> size(); j++) {
                if(inder[col[to = (*e)[j]]] == 1)
                    {flag = 1; break;}
            }
            if(flag == 0) {printf("%.6lf", 1 - (double) (ans - 1) / N); return 0;}
        }
    }
    printf("%.6lf", 1 - (double) ans / N);
    return 0;
}
/*
7 8
4 5
5 4
4 2
1 2
1 3
6 3
6 7
7 6
*/

posted @ 2018-10-22 08:19  自为风月马前卒  阅读(362)  评论(0编辑  收藏  举报

Contact with me