zoukankan      html  css  js  c++  java
  • HDU

    求确定身份的人的个数。

    只能确定狼的身份,因为只能找到谁说了谎。但一个人是否是民,无法确定。

    将人视作点,指认关系视作边,有狼边和民边两种边。

    确定狼的方法只有两种:

      1. 在一个仅由一条狼边组成的环中,狼边指向的那个点必定是狼。

      2. 环外指认铁狼为民的也必定是狼。

    所以用原图找环求情况1中的铁狼,反向建图找情况2中的狼。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn =1e5+5;
    const int INF =0x3f3f3f3f;
    struct Edge{
        int v;bool w;  
    };
    Edge G[maxn];
    vector<Edge> rG[maxn];
    int pre[maxn],dfn;
    bool isw[maxn];
    queue<int> Q;
    int res;
    
    void init(int N){
        res=0;
        memset(pre,0,sizeof(pre));
        memset(isw,0,sizeof(isw));
        for(int i=1;i<=N;++i) rG[i].clear();
    }
    
    void AddEdge(int u,int v,bool w){
        G[u] = (Edge){v,w};
        rG[v].push_back((Edge){u,w});
    }
    
    void BFS()
    {
        while(!Q.empty()){
            int u = Q.front();Q.pop();
            for(int i=0;i<rG[u].size();++i){
                Edge &e =rG[u][i];
                if(!e.w && !isw[e.v]){
                    Q.push(e.v);
                    isw[e.v] = true;
                }
            }       
        }
    }
    
    void Tarjan(int u){
        int v;bool w;
        pre[u]=2;
        v= G[u].v; 
        w = G[u].w;
        if(!pre[v])  
            Tarjan(v);
        else if(pre[v]==2){                   //找到环
            int cnt=0, tar,t;
            for(t=v;;t= G[t].v){
                Edge &e = G[t];
                if(e.w){
                    cnt++;
                    tar = G[t].v;
                }
                if(e.v==v) break;
            } 
            if(cnt==1){                    //只有一个狼边才行
                isw[tar] = true;
                Q.push(tar);
            }
        }
        pre[u]=1;
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("in.in","r",stdin);
            freopen("1009.out","w",stdout);
        #endif
        int T,N,u,v,tmp;
        char op[20];
        scanf("%d",&T);
        while(T--){
            scanf("%d",&N);
            init(N);
            for(int u=1;u<=N;++u){
                scanf("%d %s",&v,op);
                if(op[0]=='w') AddEdge(u,v,1);
                else AddEdge(u,v,0);
            }
    
            for(int i =1;i<=N;++i){
                if(!pre[i]) 
                    Tarjan(i);
            }
            BFS();
            for(int i=1;i<=N;++i)
                if(isw[i])  res++;
            printf("%d %d
    ",0,res);
        }
        return 0;
    }
    为了更好的明天
  • 相关阅读:
    centos 7 开放端口
    删除mysql 表中重复的数据
    约瑟夫问题
    Technocup 2020 Elimination Round 3题解
    DISCO Presents Discovery Channel Code Contest 2020 Qual题解
    Comet OJ
    Berlekamp-Massey算法
    CH定理与线性递推
    2020集训队作业板刷记录(一)
    模拟费用流
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9445527.html
Copyright © 2011-2022 走看看