hdu6370 werewolf 缩点+搜索

把图画一画可以发现只能判断铁狼,没有确定的村民,铁狼会存在于一个环中,这个环里面如果只有一个人被认为是狼,那么他就是铁狼,可以很容易看出这是一个基环内向树的样子,所以就会发现,如果还有人说这个铁狼是村民的话,那说这个狼是村民的人就是狼。于是就可以想到有些环是没有用的环,如果有一个环上的边都是村民边,那这个环没有卵用,直接缩掉。至于如何搜答案,可以很快想到先确定环上的狼,然后向外扩展,于是就可以反向建图,这时就是一个基环外向树的图,并且如果只加村民边的话,就形成了一个树的样子(虽然有向图这么说很不严谨,但是想不到怎么描述),并且每个点的入度最大为1,这样就可以比较方便地暴力。(爆栈,改掉了一个dfs)。

#include
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int maxn=100005;
struct edge{
    int to,nxt;
}E[maxn],e[maxn],e1[maxn],e2[maxn];
int DFN[maxn],LOW[maxn],index;
int head1[maxn],head2[maxn],head3[maxn],head4[maxn];
int S[maxn],top;
bool ins[maxn];
int col[maxn],numc;
int ecnt1,ecnt2,ecnt3,ecnt4;
void ins1(int u,int v){
    E[ecnt1].to=v;
    E[ecnt1].nxt=head1[u];
    head1[u]=ecnt1++;
}
void ins2(int u,int v){
    e[ecnt2].to=v;
    e[ecnt2].nxt=head2[u];
    head2[u]=ecnt2++;
}
void ins3(int u,int v){
    e1[ecnt3].to=v;
    e1[ecnt3].nxt=head3[u];
    head3[u]=ecnt3++;
}
void ins4(int u,int v){
    e2[ecnt4].to=v;
    e2[ecnt4].nxt=head4[u];
    head4[u]=ecnt4++;
}
void Tarjan(int u){
    DFN[u]=LOW[u]=++index;
    S[++top]=u;
    ins[u]=true;
    for(int i=head1[u];i!=-1;i=E[i].nxt){
        int v=E[i].to;
        if(!DFN[v]){
            Tarjan(v);
            LOW[u]=min(LOW[u],LOW[v]);
        }
        else if(ins[v]) LOW[u]=min(LOW[u],DFN[v]);
    }
    if(DFN[u]==LOW[u]){
        ++numc;
        while(S[top + 1]!=u){
            col[S[top]]=numc;
            ins[S[top--]]=false;
        }
    }
}
int op,n;
char str[20];
int ans;
bool vis1[maxn];
bool flag[maxn];
void dfs(int u){
    vis1[u]=1;
    for(int i=head4[u];i!=-1;i=e2[i].nxt) {if(vis1[e2[i].to]) {flag[u]=1;return;}}
    for(int i=head3[u];i!=-1;i=e1[i].nxt) {dfs(e1[i].to);}
    vis1[u]=0;
}
void bfs2(int u){
    queue<int>q;
    while(!q.empty()) q.pop();
    q.push(u);
    ans++;
    while(!q.empty()){
        u=q.front();
        q.pop();
        for(int i=head3[u];i!=-1;i=e1[i].nxt){
            q.push(e1[i].to);
            ans++;
        }
    }
}
int ind[maxn];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        numc=index=ans=ecnt1=ecnt2=ecnt3=ecnt4=0;
        top=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            vis1[i]=ind[i]=0;
            S[i]=col[i]=0;
            ins[i]=DFN[i]=LOW[i]=flag[i]=0;
            head1[i]=head2[i]=head3[i]=head4[i]=-1;
        }
        for(int i=1;i<=n;i++){
            scanf("%d%s",&op,str);
            if(str[0]=='v') ins1(op,i);
            else ins2(op,i);
        }
        for(int i=1;i<=n;i++)
        if(!DFN[i]) Tarjan(i);
        for(int j=1;j<=n;j++){
            for(int i=head1[j];i!=-1;i=E[i].nxt){
                if(col[E[i].to]!=col[j]) {ins3(col[j],col[E[i].to]);ind[col[E[i].to]]++;}
            }
            for(int i=head2[j];i!=-1;i=e[i].nxt){
                if(col[e[i].to]!=col[j]) ins4(col[j],col[e[i].to]);
            }
        }
        for(int i=1;i<=n;i++)
        if(!ind[col[i]]) {dfs(col[i]);}
        for(int i=1;i<=n;i++) if(flag[col[i]]) {bfs2(col[i]);}
        printf("0 %d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(图论)