BZOJ1823: [JSOI2010]满汉全席

题目描述

算了太长了,就不复制了

Solution

对于每种食材,只有HM两种选择
考虑2-SAT,对于每种限制条件就相当于X or Y = 1.
建边就是X’->Y, Y’->X
第一次写2-SAT感觉还不错

#include
#include
#include
using namespace std;
#define maxn 100010
inline int read(){
    int ret=0,ff=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='h') ff=-ff;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
    return ret*ff;
}
int ts(int a){
    return a>0?a<<1|1:((~a)+1)<<1;
}
struct Edge{
    int u,v,next;
}E[maxn];
int head[maxn],ecnt=0,low[maxn],ins[maxn],stk[maxn],top,dfn[maxn],ord,cnt,blg[maxn];
void addedge(int u,int v){
    E[++ecnt].u=u;
    E[ecnt].v=v;
    E[ecnt].next=head[u];
    head[u]=ecnt;
}
void Tarjan(int x){
    low[x]=dfn[x]=++ord;
    stk[++top]=x,ins[x]=1;
    for(int i=head[x];i;i=E[i].next){
        int v=E[i].v;
        if(dfn[v]==0) Tarjan(v),low[x]=min(low[x],low[v]);
        else if(ins[v]) low[x]=min(low[x],dfn[v]);
    }
    if(low[x]==dfn[x]){
        ++cnt;
        int tmp;
        do{
            tmp=stk[top--];
            ins[tmp]=0;
            blg[tmp]=cnt;
        }while(tmp!=x);
    }
}
bool ck(int n){
    for(int i=2;i<=n;i+=2){
        if(blg[i]==blg[i^1]) return 0;
    }
    return 1;
}
void init(int n){
    for(int i=0;i<=n;++i)
        head[i]=ins[i]=blg[i]=dfn[i]=low[i]=stk[i]=0;
//  memset(E,0,sizeof(E));
    ecnt=top=cnt=ord=0;
}
int main(){
    //freopen("bzoj1823.in","r",stdin);
    int T=read();
    while(T--){
        int n=read(),m=read();
        for(int i=1;i<=m;++i){
            int aa=ts(read()),bb=ts(read());
            addedge(aa^1,bb),addedge(bb^1,aa);
        }
        for(int i=2;i<=(n<<1|1);++i){
            if(dfn[i]==0)Tarjan(i);
        }
        if(ck(n<<1|1)) puts("GOOD");
        else puts("BAD");
        init(n<<1|1);
    }
}

你可能感兴趣的:(2-SAT,图论)