zoukankan      html  css  js  c++  java
  • HDU6370 Werewolf 【基环内向树】

    HDU6370 Werewolf

    题意:

    (N)个人玩狼人杀,只有村民和狼人,每个人指定另一个人并指出一个身份,其中:村民是不会说谎的,狼人是有可能说谎的,问在所有情况下必然是狼人的人数和必然是村民的人数分别有多少

    题解:

    首先所有人都有可能说谎,所以不可能有人必然是村民
    接下来我们考虑是否有人必然是狼人,我们考虑反推,即假设某个人是村民,是否产生矛盾
    首先建图,每个人向其指定的那个人连边,如果指定为狼人,边权是(1),否则边权是(0)
    可以发现,对于每一块联通块,都是一棵基环内向树,首先我们考虑环中是否有人必然是狼人
    显然如果环的权值是(1)的情况下才有可能必定存在狼人,在这个情况下,唯一被指定是狼人的那个人必定只能是狼人
    然后考虑不在环上的人,如果指定了环上的狼人为村民的话,这也必然是狼人,而且这是有传递性的,也就是如果当前人指定一个狼人是村民,那么指向这个人的人,如果也指定是村民,那那个人也是狼人,直到有人指定其父节点是狼为止

    view code
    //#pragma GCC optimize("O3")
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    
    const int MAXN = 1e5+7;
    
    int n, to[MAXN], w[MAXN], bel[MAXN];
    bool vis[MAXN];
    vector<int> G[MAXN];
    vector<int> pt[MAXN];
    void mark(int u, int id){
        bel[u] = id;
        pt[id].push_back(u);
        for(int v : G[u]) if(!bel[v]) mark(v,id);
    }
    void dfs(int u, int &__count){
        vis[u] = true;
        for(int v : G[u]){
            if(vis[v] or w[v]) continue;
            __count++;
            dfs(v,__count);
        }
    }
    int rua(int id){
        vector<int> vec;
        stack<int> stk;
        int u = pt[id][0];
        while(true){
            stk.push(u);
            vis[u] = true;
            if(vis[to[u]]){
                int tp;
                do{
                    vec.push_back(tp=stk.top());
                    stk.pop();
                }while(tp!=to[u]);
                break;
            }
            u = to[u];
        }
        int __count = 0;
        for(int x : vec) __count += w[x];
        if(__count!=1) return 0;
        for(int x : vec) if(w[x]){
            u = to[x];
            break;
        }
        for(int x : pt[id]) vis[x] = false;
        for(int x : vec) vis[x] = true;
        dfs(u,__count);
        return __count;
    }
    void solve(){
        static char buf[20];
        scanf("%d",&n);
        for(int i = 1; i <= n; i++) G[i].clear();
        for(int i = 1; i <= n; i++){
            scanf("%d %s",&to[i],buf);
            w[i] = buf[0]=='w'?1:0;
            G[i].push_back(to[i]);
            G[to[i]].push_back(i);
        }
        memset(bel+1,0,4*n);
        memset(vis+1,0,n);
        int ID = 0;
        for(int i = 1; i <= n; i++){
            if(!bel[i]){
                ++ID;
                pt[ID].clear();
                mark(i,ID);
            }
        }
        int __count = 0;
        for(int i = 1; i <= ID; i++) __count += rua(i);
        printf("%d %d
    ",0,__count);
    }
    int main(){
        int tt;
        for(scanf("%d",&tt); tt; tt--) solve();
        return 0;
    }
    
  • 相关阅读:
    二叉堆(最小堆, 最大堆)介绍与实现
    C++ 用变量定义数组
    C++ 用变量定义数组
    053185
    053184
    053183
    053182
    053181
    053180
    oracle prior
  • 原文地址:https://www.cnblogs.com/kikokiko/p/13184020.html
Copyright © 2011-2022 走看看