随笔- 22  文章- 0  评论- 10  阅读- 1579 

2-SAT问题

2SAT问题是一种在约束条件下的变量取值问题。该问题通常可以转化这样的模型:有n个变量,每一个变量只有两种取值,另有多个对这些变量的约束条件,问这些变量是否有一组取值满足所有的约束条件。

对于这类问题,我们一般的解决方案是把它抽象成一个图(如下)。这个图有2n个节点,分别是这n个变量的2种取值(视作01)。一般把图的 1~n 号节点分别设为 1~n 个变量的0取值, n+1~2n 号节点分别设为 1~n个变量的1取值。然后,我们用所给的约束条件来进行建边。如果变量a取值x时,变量b必须取值y。(xy{0,1}),那么我们就连一条从a+xnb+yn的有向边。把所有的边建好以后,对这个图跑一遍Tarjan,求出强连通分量。若存在一个n的节点kk+n在同一个强连通分量内,说明当变量取值为k的时候,他一定得取值k+n,显然矛盾,即不存在这样的一组取值使得所有约束条件被满足。反之就一定存在。

例题:[JSOI2010]满汉全席

思路:

每个厨师的两样喜好菜品可以看做一个约束条件,对于这两样菜品,如果其中一种食材已经被做成了另一样菜,那么剩下的这种食材就只能做这种菜。可以设汉式为0,满式为1,建图跑Tarjan即可。

代码:

#include<bits/stdc++.h>
#define MAXN 110
#define MAXM 1010
using namespace std;
int k,n,m,ans;
string s;
struct png
{
    int met[3],hm[3];
}p[MAXM];
struct edge
{
    int to,nxt;
}ed[MAXM<<1];
int head[MAXN<<1],tt=0;
void add(int u,int v)
{
    ed[++tt].to=v;
    ed[tt].nxt=head[u];
    head[u]=tt;
}
int dfn[MAXN<<1],low[MAXN<<1],tot=0;
stack<int>arr;
int co[MAXN<<1],col=0;
void tarjan(int st)
{
    dfn[st]=low[st]=++tot;
    arr.push(st);
    for(int i=head[st];i;i=ed[i].nxt)
    {
        int v=ed[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[st]=min(low[st],low[v]);
        }
        else if(!co[v])low[st]=min(low[st],dfn[v]);
    }
    if(low[st]==dfn[st])
    {
        co[st]=++col;
        while(!arr.empty()&&arr.top()!=st)
        {
            co[arr.top()]=col;
            arr.pop();
        }
        arr.pop();
    }
}
int num(string ss)
{
    int ret=0;
    for(int i=1;i<ss.length();i++)
        ret=ret*10+(s[i]-'0');
    return ret;
}
int main()
{
    scanf("%d",&k);
    while(k--)
    {
        scanf("%d%d",&n,&m);
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(co,0,sizeof(co));
        memset(ed,0,sizeof(ed));
        memset(head,0,sizeof(head));
        tt=tot=col=0;
        while(!arr.empty())arr.pop();
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=2;j++)
            {
                cin>>s;
                if(s[0]=='h')p[i].hm[j]=0;
                else p[i].hm[j]=1;
                p[i].met[j]=num(s);
            }
            add(p[i].met[1]+(!p[i].hm[1])*n,p[i].met[2]+p[i].hm[2]*n);
            add(p[i].met[2]+(!p[i].hm[2])*n,p[i].met[1]+p[i].hm[1]*n);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i);
        bool flag=0;
        for(int i=1;i<=n;i++)
            if(co[i]==co[i+n])flag=1;
        if(!flag)printf("GOOD\n");
        else printf("BAD\n");
    }
    return 0;
}
 posted on   hu_led  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示