1823: [JSOI2010]满汉全席 2-SAT

学了一发2-SAT,感觉还是比较好理解的。
伍昱 由对称性解2-sat问题(ppt)
【研究总结】2-sat问题
推荐这个ppt和这个blog。

那么这道题就是一道裸题啦。
把汉式料理和满式料理看做点,满足的条件是至少选一个,也就是每次读入u,v,要连边u’->v,v’->u,代表若不选u必选v,若不选v必选u。跑2-SAT就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,cnt,tot,top,scc,flag,Case;
int head[205],dfn[205],low[205],stack[205],belong[205];
bool inset[205];
int next[2005],list[2005];
inline int read()
{
    int a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
inline int init()
{
    char c=getchar();
    while (c!='m'&&c!='h') c=getchar();
    if (c=='m') return read()*2;
    return read()*2+1;
}
inline void insert(int x,int y)
{
    next[++cnt]=head[x];
    head[x]=cnt;
    list[cnt]=y;
}
void dfs(int x)
{
    dfn[x]=low[x]=++tot;
    stack[++top]=x;
    inset[x]=1;
    for (int i=head[x];i;i=next[i])
        if (!dfn[list[i]])
        {
            dfs(list[i]);
            low[x]=min(low[x],low[list[i]]);
        }
        else if (inset[list[i]]) low[x]=min(low[x],dfn[list[i]]);
    if (low[x]==dfn[x])
    {
        int i=-1; scc++;
        while (i!=x)
        {
            i=stack[top--];
            inset[i]=0;
            belong[i]=scc;
        }
    }
}
inline void tarjan()
{
    for (int i=2;i<=2*n+1;i++) if (!dfn[i]) dfs(i);
}
int main()
{
    Case=read();
    while (Case--)
    {
        n=read(); m=read();
        flag=top=cnt=tot=scc=0;
        memset(head,0,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        for (int i=1;i<=m;i++)
        {
            int u=init(),v=init();
            insert(u^1,v); insert(v^1,u);
        }
        tarjan();
        for (int i=1;i<=n;i++)
            if (belong[2*i]==belong[2*i+1]) {flag=1; break;}
        flag?puts("BAD"):puts("GOOD");
    }
    return 0;
}

你可能感兴趣的:(1823: [JSOI2010]满汉全席 2-SAT)