zoukankan      html  css  js  c++  java
  • P4819 [中山市选]杀人游戏

    P4819 中山市选 杀人游戏
    简单来说就是找到入度为0的点记为 (cnt)
    那么我们可以缩点直接找,不然复杂度爆炸。
    答案是 (ans = 1.0 - frac{cnt}{N}) (这是错的)
    但是这是错的,因为少考虑一种情况。
    你是可以推理的!!!!!!!!
    那末,我们考虑这样一组数据

    100 0
    

    答案显然是1%(只有最后一个人不是杀手),因为你要一个人一个人去查,那末你只用查99个人,最后一个人是不是杀手就显然。
    形式化的,当且仅当一个人不会影响调查,而且缩点后 (siz = 1) 的时候,他可以被推理出来,但是你只能选一个这样的点(显然)。
    所以记一个 (flag) 看有没有这样的人。
    真实答案就是 (ans = 1.0 - frac{cnt - flag}{N})
    然后要去掉重边(缩点后的)。

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <stack>
    #include <map>
    
    using namespace std;
    
    typedef long long ll;
    const ll MAXN = 1e6+10;
    
    ll N, M;
    
    struct edge {
        ll nt, to;
    } E[MAXN], E2[MAXN];
    
    ll ind[MAXN], ond[MAXN], siz[MAXN];
    ll head[MAXN], cnt = -1, dfn[MAXN], low[MAXN], num, vis[MAXN], _N, head2[MAXN], cnt2 = -1, bel[MAXN];
    stack <ll> st;
    map <ll, ll> m[MAXN];
    
    void add(ll, ll);
    void add2(ll, ll);
    void rebuild();
    void tarjan(ll);
    bool iss(ll);
    
    int main() {
        memset(head2, -1, sizeof(head2));
        memset(head, -1, sizeof(head));
        scanf("%lld%lld", &N, &M);
        for (ll x, y, i = 1; i <= M; i++) {
            scanf("%lld%lld", &x, &y);
            add(x, y);
        }
        for (ll i = 1; i <= N; i++) {
        	if (!dfn[i])
            	tarjan(i);
        }
        rebuild();
        ll ct = 0, flag = 0;
        for (ll i = 1; i <= _N; i++) {
            if (!ind[i]) {
                ct++;
            	if (siz[i] == 1 && (!ond[i] || iss(i))) {
            		flag = 1;	
            	}
    		}
        }
        printf("%.6f", 1.0 - (1.0 * (ct - flag) / N));
        return 0;
    }
    
    bool iss(ll n) {
    	for (ll i = head2[n]; ~i; i = E2[i].nt) {
    		ll v = E2[i].to;
    		if (ind[v] == 1) return false;
    	}
    	return true;
    }
    
    void rebuild() {
        for (ll i = 1; i <= N; i++) {
            for (ll j = head[i]; ~j; j = E[j].nt) {
                ll v = E[j].to;
                if (bel[v] != bel[i]) {
                	if (m[bel[i]][bel[v]]) continue;
                	m[bel[i]][bel[v]] = 1;
                    add2(bel[i], bel[v]);
                    ind[bel[v]]++;
                    ond[bel[i]]++;
                }
            }
        }
    }
    
    void add2(ll x, ll y) {
        cnt2++;
        E2[cnt2].to = y;
        E2[cnt2].nt = head2[x];
        head2[x] = cnt2;
    }
    
    void tarjan(ll n) {
        dfn[n] = low[n] = ++num;
        st.push(n);
        for (ll i = head[n]; ~i; i = E[i].nt) {
            ll v = E[i].to;
            if (vis[v]) continue;
            if (dfn[v]) {
                low[n] = min(dfn[v], low[n]);
            } else {
                tarjan(v);
                low[n] = min(low[n], low[v]);
            }
        }
        if (low[n] == dfn[n]) {
            ll t;
            _N++;
            do {
                t = st.top(); st.pop();
                bel[t] = _N;
                vis[t] = 1;
                siz[_N]++;
            } while (t != n);
        }
    }
    
    void add(ll x, ll y) {
        cnt++;
        E[cnt].to = y;
        E[cnt].nt = head[x];
        head[x] = cnt;
    }
    
    Yukkuri si te yi te ne
  • 相关阅读:
    如何唤醒一个处于阻塞状态下的线程
    如何终止一个线程
    网络编程基础_5.1聊天室-客户端
    网络编程基础_4.2TCP-客户端
    网络编程基础_4.1TCP_服务端
    网络编程基础_3.APC队列
    网络编程基础_2.等待事件
    网络编程基础_1.等待句柄
    Window提高_3.1练习_双进程守护
    Windows提高_2.3第三部分:内核区同步
  • 原文地址:https://www.cnblogs.com/Gensokyo-Alice/p/13689919.html
Copyright © 2011-2022 走看看