洛谷 P4171 [JSOI]满汉全席

洛谷

最近刚刚学的2-sat,就刷了这道裸题。

2-sat问题一般是用tarjan求的,当出现(x,y)或(!x,y)或(x,!y)三种选择时,我们可以把!x->y,!y->x连边。

然后直接tarjan。

比如这一题,设汉菜为是,满菜为非,直接按上面所述连边跑tarjan,判断是与非是否在同一强连通分量中。

在,就输出BAD,不在,则输出GOOD。

code:

#include <bits/stdc++.h>
using namespace std;

const int N=10005;
int n,m,dfscnt,scc;
int s[N<<5][2],o[N];
int dfn[N],low[N],sccno[N];
stack <int> sta;

void add(int x,int y)
{
    s[++o[0]][1]=o[x],s[o[0]][0]=y,o[x]=o[0];
}

void tarjan(int x)
{
    sta.push(x);
    low[x]=dfn[x]=++dfscnt;
    for (int i=o[x];i;i=s[i][1]) {
        int y=s[i][0];
        if (!dfn[y])
            tarjan(y),low[x]=min(low[x],low[y]);
        else if (!sccno[y])
            low[x]=min(low[x],dfn[y]);
    }
    if (dfn[x]==low[x]) {
        ++scc;
        while (1) {
            int y=sta.top();
            sta.pop();
            sccno[y]=scc;
            if (x==y) break;
        }
    }
}

int main()
{
    int T;cin>>T;
    while (T--) {
        memset(o,0,sizeof(o));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(sccno,0,sizeof(sccno));
        scc=dfscnt=0;
        scanf("%d%d",&n,&m);
        char a,b;
        int pa,pb;
        for (int i=1;i<=m;++i) {
            cin>>a>>pa>>b>>pb;
            int aval,bval,nota,notb;
            if (a=='h') aval=1;
            else aval=0;
            if (b=='h') bval=1;
            else bval=0;
            nota=aval^1,notb=bval^1;
            add(pa+nota*n,pb+bval*n);
            add(pb+notb*n,pa+aval*n);
        }
        for (int i=1;i<=(n<<1);++i)
            if (!dfn[i]) tarjan(i);
        bool flag=1;
        for (int i=1;i<=n;++i)
            if (sccno[i]==sccno[i+n]) {
                puts("BAD");
                flag=0;
                break;
            }
        if (flag) puts("GOOD");
    }
    return 0;
}
posted @ 2018-08-21 20:39  fuyan0101  阅读(138)  评论(1编辑  收藏  举报