2-SAT

来源:互联网 发布:网络打鱼秘籍 编辑:程序博客网 时间:2024/06/07 18:04

关于2-SAT问题:

SAT是Satisfiability(适应性)的缩写,SAT问题(适应性问题)指的是给出一些条件(元素经过逻辑运算的结果),问是否存在一种合法的方案使得其满足所有的条件。SAT问题已经被证明是一个NP完全问题
2-SAT问题是一种特殊的SAT问题,一般形如:给出n个元素,每个元素有两种取值,元素之间存在着一些关系且这种关系是对称的,判断有没有合法解
关系是指形如“若A取值为x则B必须取值为y”这样的条件
【摘自学长的PPT】

建图:
将每个元素拆成a0,a1分别代表它的两种取值
(将节点xi拆分成2i,2*i+1,这样两个拆分成的点满足一个点的序号分别为y,y^1)
(假设标记2i为真,2i+1为假)
对于题中所给的限制关系:如若xi为假,则xj为真
那么我们可以连一条2i向2j+1的有向边,再从2j向2i+1连一条边

如何判断是否合法?
不难发现,如果两个点是联通的,则可以证明它们是可以同时满足的,所以如果对于一个点i,它拆分成的点2i,2i+1在同一个强连通分量里,则说明它们是可以同时存在的,这和已知相悖,所以该问题无解。

所以建完图后用tarjan就可以求出是否有解了。

一道水题:
BZOJ 1823
看到题面就晕系列,然而概括能力太差所以还是把它直接贴上来把23333
Description

满汉全席是中国最丰盛的宴客菜肴,有许多种不同的材料透过满族或是汉族的料理方式,呈现在數量繁多的菜色之中。由于菜色众多而繁杂,只有极少數博学多闻技艺高超的厨师能够做出满汉全席,而能够烹饪出经过专家认证的满汉全席,也是中国厨师最大的荣誉之一。 世界满汉全席协会是由能够料理满汉全席的专家厨师们所组成,而他们之间还细分为许多不同等级的厨师。为了招收新进的厨师进入世界满汉全席协会,将于近日举办满汉全席大赛,协会派遣许多会员当作评审员,为的就是要在參赛的厨师之中,找到满汉料理界的明日之星。 大会的规则如下:每位參赛的选手可以得到n 种材料,选手可以自由选择用满式或是汉式料理将材料当成菜肴。大会的评审制度是:共有m 位评审员分别把关。每一位评审员对于满汉全席有各自独特的見解,但基本见解是,要有兩样菜色作为满汉全席的标志。如某评审认为,如果没有汉式东坡肉跟满式的涮羊肉锅,就不能算是满汉全席。但避免过于有主見的审核,大会规定一个评审员除非是在认为必备的两样菜色都没有做出來的狀况下,才能淘汰一位选手,否则不能淘汰一位參赛者。换句话說,只要參赛者能在这兩种材料的做法中,其中一个符合评审的喜好即可通过该评审的审查。如材料有猪肉,羊肉和牛肉时,有四位评审员的喜好如下表: 评审一 评审二 评审三 评审四 满式牛肉 满式猪肉 汉式牛肉 汉式牛肉 汉式猪肉 满式羊肉 汉式猪肉 满式羊肉 如參赛者甲做出满式猪肉,满式羊肉和满式牛肉料理,他将无法满足评审三的要求,无法通过评审。而參赛者乙做出汉式猪肉,满式羊肉和满式牛肉料理,就可以满足所有评审的要求。 但大会后來发现,在这样的制度下如果材料选择跟派出的评审员没有特别安排好的话,所有的參赛者最多只能通过部分评审员的审查而不是全部,所以可能会发生没有人通过考核的情形。如有四个评审员喜好如下表时,则不論參赛者采取什么样的做法,都不可能通过所有评审的考核: 评审一 评审二 评审三 评审四 满式羊肉 满式猪肉 汉式羊肉 汉式羊肉 汉式猪肉 满式羊肉 汉式猪肉 满式猪肉 所以大会希望有人能写一个程序來判断,所选出的m 位评审,会不会发生 没有人能通过考核的窘境,以便协会组织合适的评审团。

Input

第一行包含一个数字 K,代表测试文件包含了K 组资料。每一组测试资料的第一行包含兩个数字n 跟m(n≤100,m≤1000),代表有n 种材料,m 位评审员。为方便起見,材料舍弃中文名称而给予编号,编号分别从1 到n。接下來的m 行,每行都代表对应的评审员所拥有的兩个喜好,每个喜好由一个英文字母跟一个数字代表,如m1 代表这个评审喜欢第1 个材料透过满式料理做出來的菜,而h2 代表这个评审员喜欢第2 个材料透过汉式料理做出來的菜。每个测试文件不会有超过50 组测试资料

Output

每笔测试资料输出一行,如果不会发生没有人能通过考核的窘境,输出GOOD;否则输出BAD(大写字母)。

Sample Input

2

3 4

m3 h1

m1 m2

h1 h3

h3 m2

2 4

h1 m2

m2 m1

h1 h2

m1 h2

Sample Output

GOOD

BAD

2-SAT的裸题。
打的时候各种浑浑噩噩23333最后打完了思路还清晰多了。

//这是一份我打完了都不知道自己在打什么的代码 #include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int N = 10010;const int M = 10010;inline int Min(int a,int b){    return a<b?a:b;}int k;int n,m;char s[N];struct node{    int pre,v;}edge[N*10];int num=0;int head[N*10];void addedge(int from,int to){    num++;    edge[num].pre=head[from];    edge[num].v=to;    head[from]=num;}int indx=0;int dfn[N],low[N];bool vis[N];int tail=0,stack[N];int cnt=0,place[N];void tarjan(int u){    indx++;    dfn[u]=low[u]=indx;vis[u]=true;    tail++;stack[tail]=u;    for(int i=head[u];i;i=edge[i].pre){        int v=edge[i].v;        if(!dfn[v]){            tarjan(v);            low[u]=Min(low[u],low[v]);        }        else if(vis[v]) low[u]=Min(low[u],dfn[v]);    }    if(low[u]==dfn[u]){        int x=0;cnt++;        while(x!=u){            x=stack[tail];            place[x]=cnt;            tail--;            vis[x]=false;        }    }}#define ms(x,y) memset(x,y,sizeof(x))void update(){    indx=0,tail=0,cnt=0,num=0;    ms(dfn,0);ms(low,0);ms(vis,0);ms(head,0);ms(edge,0);    ms(place,0);}int main(){    scanf("%d",&k);    while(k--){        update();        scanf("%d%d",&n,&m);        int nn=n<<1;        for(int i=1;i<=m;i++){            char a1,a2;            int b1,b2;            int x,y;            cin>>a1;scanf("%d",&b1);            cin>>a2;scanf("%d",&b2);            if(a1=='h') b1=(b1<<1)+1;else b1=b1<<1;            if(a2=='h') b2=(b2<<1)+1;else b2=b2<<1;            x=b1^1,y=b2^1;            addedge(x,b2);addedge(y,b1);        }        for(int i=1;i<=nn;i++)           if(!dfn[i]) tarjan(i);        int t=1;        for(int i=1;i<=n;i++){            int b1=i<<1;            if(place[b1]==place[b1^1]){                t=0;                printf("BAD\n");                break;            }        }        if(t==1) printf("GOOD\n");    }    return 0;}

扩展:
判断某个元素的取值是否确定
如果2i这个点可取,那么再加入(2i+1,2i)这条边后仍合法。
如果2i+1这个点可取,那么再加入(2i,2i+1)这条边后仍合法。
如果二者皆合法,那么取值不确定

求可行解
我们可以从1到n枚举元素,再枚举取值,如果这种取值是合法的,就继续下去,否则就取另外一种取值,然后继续下去
由于是否合法可以及时判断,所以没有回溯的过程,时间复杂度是O(NM)的······
但是他可以用来求字典序最小的可行解

原创粉丝点击