2-sat

一道2-sat的水题
https://vjudge.net/contest/176902#problem/B

一直不太清楚2-sat是什么,不过貌似已经掌握用dfs判2-sat的方法。

#include<bits/stdc++.h>
#define pb push_back 
#define mp make_pair
using namespace std;

const int maxn=1;
typedef long long ll;

int n,m,ans;

int e[58][58],e2[58][58]; 
int f[58],g[58];

void cpy()
{
    int i,j;

    for(i=1;i<=52;++i) g[i]=f[i];
    for(i=1;i<=52;++i)
      for(j=1;j<=52;++j)
        e2[i][j]=e[i][j];
}

int f2[56];

bool dfs(int x)
{
    int i,j,k;
    for(i=1;i<=52;++i)
    {
        if(x!=i&&e2[x][i])
        {
            if(g[x]==-g[i])
            {
                if(f2[i]==0)
                {
                    f2[i]=1;
                    if(!dfs(i)) return 0;
                }
            }
            if(g[x]==g[i]) return 0;
            if(g[i]==0) 
            {
                g[i]=-g[x];
                f2[i]=1;
                if(!dfs(i)) return 0;
            }
        }
    }
    return 1;
}

bool check()
{
    int i,j,k;
    memset(f2,0,sizeof(f2));
    for(i=1;i<=52;++i)
    {
        if(!f2[i]&&g[i]!=0)
        {
            f2[i]=1;
            if(!dfs(i))
              return 0;
        }
    }
    for(i=1;i<=52;++i)
    {
        if(!f2[i]&&g[i]==0)
        {
            f2[i]=1;
            g[i]=1;
            if(!dfs(i))
              return 0;
        }
    }
    /*
    for(i=1;i<=52;++i)
      for(j=1;j<=52;++j)
      {
        if(i!=j)
        {
            if(e2[i][j]&&f2[i]&&f2[j]&&g[i]==g[j]) return 0;
        }
      }*/
    return 1;

}

int main()
{
    int i,j,k;
    scanf("%d",&n);
    for(i=1;i<=n;++i)
    {
        string t;
        cin>>t;
        int x=t[0]-'A'+1;
        int y=t[1]-'A'+1;
        cin>>j>>k;
        if(j==2) x+=26,y+=26;
        if(k==0)
        {
            if(f[x]==1||f[y]==1) return 0*printf("0\n");
            f[x]=f[y]=-1;
        }
        else if(k==2)
        {
            if(f[x]==-1||f[y]==-1) return 0*printf("0\n");
            f[x]=f[y]=1;
        }
        else
        {
            e[x][y]=e[y][x]=1;
        }
    }

    cpy();


    if(!check())
    {
        return 0*printf("0\n");
    }


    for(i=1;i<=26;++i)
      e[i][i+26]=e[i+26][i]=1;



    for(i=1;i<=26;++i)
      for(j=i+1;j<=26;++j)
        for(k=j+1;k<=26;++k)
        {
            if(f[i]==1||f[j]==1||f[k]==1||f[i+26]==1||f[j+26]==1||f[k+26]==1) continue;

            cpy();

            g[i]=-1;
            g[j]=-1;
            g[k]=-1;
            g[i+26]=-1;
            g[j+26]=-1;
            g[k+26]=-1;
            e2[i][i+26]=e2[i+26][i]=0;
            e2[j][j+26]=e2[j+26][j]=0;
            e2[k][k+26]=e2[k+26][k]=0;
            if(check()) ans++;
        }

    printf("%d\n",ans);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值