bzoj1823: [JSOI2010]满汉全席

2-SAT。

好像很复杂的样子所以还在慢慢摸索。。。

这道题只需要tarjan缩点就可以了,如果有一个材料的满式和汉式同时被选中,代表不可能实现。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 5000 + 10;
int g[maxn],v[maxn],next[maxn],eid;
int n,m,T;
int dfn[maxn],low[maxn],vid;
int vis[maxn];
int s[maxn],sp;
int color[maxn],cid;
char c1,c2;

int addedge(int a,int b) {
    v[eid]=b; next[eid]=g[a]; g[a]=eid++;
}

void tarjan(int u) {
    dfn[u]=low[u]=++vid;
    s[++sp]=u; vis[u]=1;
    for(int i=g[u];~i;i=next[i]) {
        if(vis[v[i]]==0) {
            tarjan(v[i]);
            low[u]=min(low[u],low[v[i]]);    
        }
        else if(vis[v[i]]==1) {
            low[u]=min(low[u],dfn[v[i]]);
        }
    }
    
    if(dfn[u]==low[u]) {
        ++cid;
        do {
            color[s[sp]]=cid;
            vis[s[sp]]=2;
        }while(s[sp--]!=u); 
    }
}

int main() {
    scanf("%d",&T);
    while(T--) {
        memset(g,-1,sizeof(g)); eid=0;
        scanf("%d%d",&n,&m);
        for(int i=1,x,y;i<=m;i++) {
            scanf("\n%c%d %c%d",&c1,&x,&c2,&y);    
            x=(x<<1)+(c1=='h');
            y=(y<<1)+(c2=='h');
            addedge(x^1,y);
            addedge(y^1,x);
        }
        memset(color,0,sizeof(color)),cid=0;
        memset(vis,0,sizeof(vis)),vid=0;
        for(int i=2;i<=((n<<1)|1);i++) if(!vis[i]) tarjan(i);
        
        bool flag=true;
        for(int i=1;i<=n;i++) if(color[i<<1]==color[(i<<1)|1]) {
            flag=false; break;
        }
        if(flag) printf("GOOD\n");
        else printf("BAD\n");
    }
    return 0;    
}
posted @ 2016-07-07 18:39  invoid  阅读(310)  评论(0编辑  收藏  举报