2011ACM成都赛区现场赛E题 (2-sat) (SPOJ9939)

这是我最痛心的一道题,就是少了四句话,忘了加上矛盾而已,导致了我们队的滑铁卢。想想我还是算擅长图论的,这么典型的2-sat题还不过,真的很不应该,面壁……

#include <stdio.h>
#include <cstring>
using namespace std;
struct gtype {
       int y,next;
}g[1000100];
int first[20010],tt,n,m,tot,a[10010],x,y,k;
int low[20010],dfn[20010],stk[20010],cnt[20010],id,idx,end;
void add(int x,int y) {
    tot++;
    g[tot].y=y;
    g[tot].next=first[x];
    first[x]=tot;
}
void tarjan(int u) {
    low[u]=dfn[u]=++idx;
    stk[++end]=u;
    for(int x=first[u];x!=-1;x=g[x].next) {
        int v=g[x].y;
        if (!dfn[v]) {
            tarjan(v);
            if (low[u]>low[v]) low[u]=low[v];
        }
        else if (cnt[v]==0 && low[u]>dfn[v]) low[u]=dfn[v];
    }
    if(low[u]==dfn[u]) {
        ++id;
        do {
           cnt[stk[end]]=id;
        }while(u!=stk[end--]);
    }
}
void did(int x,int y,int k) {
     int a1=a[x],a2=(a[x]+1)%3;
     if (a2==0) a2=3;
     int b1=a[y],b2=(a[y]+1)%3;
     if (b2==0) b2=3;
     
     if (k==0) {
               if (a1==b1) add(x,y),add(y,x),add(x+n,y+n),add(y+n,x+n);
               else if (a2==b1) add(x+n,y),add(y,x+n),add(x,x+n),add(y+n,y);
               else add(x,y+n),add(y+n,x),add(x+n,x),add(y,y+n);
     }
     else {
               if (a1==b1) add(x,y+n),add(y+n,x),add(y,x+n),add(x+n,y);
               else if (a2==b1) add(y,x),add(x+n,y+n);
               else add(x,y),add(y+n,x+n);
     }
}
int main() {
    scanf("%d",&tt);
    for (int cas=1;cas<=tt;cas++) {
        scanf("%d%d",&n,&m);
        tot=0;
        memset(g,0,sizeof(g));
        memset(first,-1,sizeof(first));
        
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for (int i=1;i<=m;i++) {
                 scanf("%d%d%d",&x,&y,&k);
                 if (k==1) did(x,y,1);
                 else did(x,y,0);
        }
        
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(cnt,0,sizeof(cnt));       
        id=idx=end=0;
        for (int i=1;i<=2*n;i++)
            if (!dfn[i]) tarjan(i);
        bool yes=true;
        for (int i=1;i<=n;i++)
            if (cnt[i]==cnt[i+n]) {
               yes=false;
               break;
            }
        printf("Case #%d: ",cas);
        if (yes) printf("yes\n");
        else printf("no\n");
    }
    return 0;
}    


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值