2-SAT:有趣的图论模型

什么是2-SAT

SAT是适定性(Satisfiability)问题的简称。之所以研究2-sat是因为当k>2时,k-sat问题已经被证明是NPC的了。

2-sat问题简单来说就是有$n$个二元集合,其中一些元素不能同时取到,问每个集合各取一个的方案。

至于2-sat的算法,就是将不能同时取元素的限制转为有向边,再跑一遍tarjan(如果要求判断可行性);或者dfs判断是否冲突(求方案)。

难就难在建模吧……或者说其他难点我还没学会?

这里有一篇论文2-sat问题和一篇博客【研究总结】2-sat问题,先攒着吧……

一些例题

【小技巧转化】bzoj1823: [JSOI2010]满汉全席

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(大写字母)。


题目分析

感觉那年出题人……很亦可赛艇啊。

这里的二元组限制变成了必须选一种,但是实际上转化一下就是一样的。

例如m3和h1必须选一种,那么等价于选m3必选h1;选m1必选m3。于是直接用tarjan判断可行性就好了。

 /**************************************************************
    Problem: 1823
    User: AntiQuality
    Language: C++
    Result: Accepted
    Time:68 ms
    Memory:1324 kb
****************************************************************/
 
#include<bits/stdc++.h>
const int maxn = ;
const int maxm = ;
 
int tt,n,m;
int tim,dfn[maxn],low[maxn];
int stk[maxn],cnt,col[maxn],cols;
int edgeTot,edges[maxm],nxt[maxm],head[maxn];
 
int read()
{
    char ch = getchar();
    int num = , fl;
    for (; !isalpha(ch); ch = getchar());
    fl = (ch=='h'?:n);
    for (; !isdigit(ch); ch = getchar());
    for (; isdigit(ch); ch = getchar())
        num = (num<<)+(num<<)+ch-;
    return num+fl;
}
inline int ene(int x){return x>n?x-n:x+n;}
void addedge(int u, int v)
{
    edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
}
void tarjan(int u)
{
    dfn[u] = low[u] = ++tim;
    stk[++cnt] = u;
    for (int i=head[u]; i!=-; i=nxt[i])
    {
        int v = edges[i];
        if (!dfn[v])
            tarjan(v), low[u] = std::min(low[u], low[v]);
        else if (!col[v])
            low[u] = std::min(low[u], dfn[v]);
    }
    if (dfn[u]==low[u]){
        col[u] = ++cols;
        for (; stk[cnt]!=u; cnt--)
            col[stk[cnt]] = cols;
        cnt--;
    }
}
int main()
{
    scanf("%d",&tt);
    while (tt--)
    {
        edgeTot = cnt = cols = tim = ;
        memset(head, -, sizeof head);
        memset(dfn, , sizeof dfn);
        memset(col, , sizeof col);
        scanf("%d%d",&n,&m);
        for (int i=; i<=m; i++)
        {
            int u = read(), v = read();
            addedge(ene(u), v);
            addedge(ene(v), u);
        }
        for (int i=; i<=*n; i++)
            if (!dfn[i]) tarjan(i);
        bool fl = ;
        for (int i=; i<=n; i++)
            if (col[i]==col[i+n]){
                fl = ;
                break;
            }
        if (fl) puts("GOOD");
        else puts("BAD");
    }
    return ;
}

hdu1814Peaceful Commission

Problem Description

The Public Peace Commission should be legislated in Parliament of The Democratic Republic of Byteland according to The Very Important Law. Unfortunately one of the obstacles is the fact that some deputies do not get on with some others.

The Commission has to fulfill the following conditions: 
1.Each party has exactly one representative in the Commission, 
2.If two deputies do not like each other, they cannot both belong to the Commission.

Each party has exactly two deputies in the Parliament. All of them are numbered from 1 to 2n. Deputies with numbers 2i-1 and 2i belong to the i-th party .

Task

Write a program, which: 
1.reads from the text file SPO.IN the number of parties and the pairs of deputies that are not on friendly terms, 
2.decides whether it is possible to establish the Commission, and if so, proposes the list of members, 
3.writes the result in the text file SPO.OUT. 

Input

In the first line of the text file SPO.IN there are two non-negative integers n and m. They denote respectively: the number of parties, 1 <= n <= 8000, and the number of pairs of deputies, who do not like each other, 0 <= m <=2 0000. In each of the following m lines there is written one pair of integers a and b, 1 <= a < b <= 2n, separated by a single space. It means that the deputies a and b do not like each other. 
There are multiple test cases. Process to end of file. 

Output

The text file SPO.OUT should contain one word NIE (means NO in Polish), if the setting up of the Commission is impossible. In case when setting up of the Commission is possible the file SPO.OUT should contain n integers from the interval from 1 to 2n, written in the ascending order, indicating numbers of deputies who can form the Commission. Each of these numbers should be written in a separate line. If the Commission can be formed in various ways, your program may write mininum number sequence. 

题目大意

有n个党派,每个党派只有2人,现要设立一个和平委员会,必须满足如下条件;

  • 每个党派在委员会中恰有一个代表
  • 如果两个代表互相反感,那么他们都不能属于委员会。

求可行性以及字典序最小方案

题目分析

嘛……最早我做的时候第一问用的tarjan缩点,第二问瞎搞:对于每一个入度为零的点先做一遍dfs以确定它之后以及它自己是否合法。

但是可能思路有点乱写挂了好久……花了好几个小时都没弄出来。

后来在网上发现一种比较好的思路:其实就是最上面提到的dfs方法。显而易见dfs过程中可以判断可行性,那么为什么还要去写个没什么其他用处的tarjan呢?

这里的dfs跟我最早想的dfs也一样(所以不清楚我到底哪里写挂),通过子节点合法性回溯回查找节点。不过这样总的来说就可以按照顺序进行而不用考虑乱七八糟的东西了。

 bool dfs(int x)
{
if (vis[ene(x)]) return ;
if (vis[x]) return ;
vis[x] = , stk[++cnt] = x;
for (int i=head[x]; i!=-; i=nxt[i])
if (!dfs(edges[i])) return ;
return ;
}

这里是dfs判断的代码。

所以其实是60来行就可以搞定的事情。

 #include<bits/stdc++.h>
const int maxn = ;
const int maxm = ; int n,m;
int edges[maxm],nxt[maxm],head[maxn],edgeTot;
int stk[maxn],cnt;
bool vis[maxn]; int read()
{
char ch = getchar();
int num = ;
bool fl = ;
for (; !isdigit(ch); ch = getchar())
if (ch=='-') fl = ;
for (; isdigit(ch); ch = getchar())
num = (num<<)+(num<<)+ch-;
if (fl) num = -num;
return num;
}
inline int ene(int x){return ((x-)^)+;}
void addedge(int u, int v)
{
edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
}
bool dfs(int x)
{
if (vis[ene(x)]) return ;
if (vis[x]) return ;
vis[x] = , stk[++cnt] = x;
for (int i=head[x]; i!=-; i=nxt[i])
if (!dfs(edges[i])) return ;
return ;
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF&&n&&m)
{
memset(vis, , sizeof vis);
memset(head, -, sizeof head);
cnt = edgeTot = ;
for (int i=; i<=m; i++)
{
int x = read(), y = read();
addedge(x, ene(y)), addedge(y, ene(x));
}
bool fl = ;
for (int i=; i<=n; i++)
if (!vis[*i]&&!vis[*i-]){
cnt = ;
if (!dfs(*i-)){
while (cnt) vis[stk[cnt]] = , cnt--;
if (!dfs(*i)){
fl = ;
break;
}
}
}
if (fl){
for (int i=; i<=*n; i++)
if (vis[i]) printf("%d\n",i);
}else puts("NIE");
}
return ;
}

END

初涉2-SAT的更多相关文章

  1. 多边形碰撞 -- SAT方法

    检测凸多边形碰撞的一种简单的方法是SAT(Separating Axis Theorem),即分离轴定理. 原理:将多边形投影到一条向量上,看这两个多边形的投影是否重叠.如果不重叠,则认为这两个多边形 ...

  2. Struts2拦截器初涉

    Struts2拦截器初涉 正在练习struts,本例是从一个pdf上摘抄的例子,那本pdf都不知道叫什么名字,不过感觉很适合初学者. 在这里要实现一个简单的拦截器"GreetingInter ...

  3. 初涉SQL Server性能问题(4/4):列出最耗资源的会话

    在上3篇文章里,我们讨论了列出反映服务器当前状态的不同查询. 初涉SQL Server性能问题(1/4):服务器概况 初涉SQL Server性能问题(2/4):列出等待资源的会话 初涉SQL Ser ...

  4. 初涉SQL Server性能问题(3/4):列出阻塞的会话

    在 初涉SQL Server性能问题(2/4)里,我们讨论了列出等待资源或正运行的会话脚本.这篇文章我们会看看如何列出包含具体信息的话阻塞会话清单. /************************ ...

  5. 初涉SQL Server性能问题(2/4):列出等待资源的会话

    在初涉SQL Server性能问题(1/4)里,我们知道了如何快速检查服务器实例上正运行的任务数和IO等待的任务数.这个是轻量级的脚本,不会给服务器造成任何压力,即使服务器在高负荷下,也可以正常获得结 ...

  6. 【AS3 Coder】任务七:初涉PureMVC——天气预报功能实现

    转自:http://www.iamsevent.com/post/36.html AS3 Coder]任务七:初涉PureMVC——天气预报功能实现 使用框架:AS3任务描述:了解PureMVC框架使 ...

  7. 初涉JavaScript模式系列 阶段总结及规划

    总结 不知不觉写初涉JavaScript模式系列已经半个月了,没想到把一个个小点进行放大,竟然可以发现这么多东西. 期间生怕对JS的理解不到位而误导各位,读了很多书(个人感觉JS是最难的oo语言),也 ...

  8. POJ 3678 Katu Puzzle(2 - SAT) - from lanshui_Yang

    Description Katu Puzzle is presented as a directed graph G(V, E) with each edge e(a, b) labeled by a ...

  9. 初涉IPC,了解AIDL的工作原理及使用方法

    初涉IPC,了解AIDL的工作原理及使用方法 今天来讲讲AIDL,这个神秘的AIDL,也是最近在学习的,看了某课大神的讲解写下的blog,希望结合自己的看法给各位同价通俗易懂的讲解 官方文档:http ...

  10. Map Labeler POJ - 2296(2 - sat 具体关系建边)

    题意: 给出n个点  让求这n个点所能建成的正方形的最大边长,要求不覆盖,且这n个点在正方形上或下边的中点位置 解析: 当然是二分,但建图就有点还行..比较难想..行吧...我太垃圾... 2 - s ...

随机推荐

  1. 如何找出nginx配置文件的所在位置?

    对于一台陌生的服务器或安装太久忘了位置,怎么才能简单快速的找到配置文件的位置呢?要找出配置文件的位置,需要先找出nginx可执行文件的路径 , 这里有几种方法: 1.如果程序在运行中 ps -ef | ...

  2. math(2018.10.27)

    20%的数据直接暴搜就行,接下来我们考虑哪些数不能够出现在同一个集合中,就连一 条边,我们会发现前

  3. CentOS7-MySQL8安装-使用yum库安装

    # Enable to use MySQL 5.5 [mysql55-community] name=MySQL 5.5 Community Server baseurl/$basearch/ ena ...

  4. log4j和log4j2怎么动态加载配置文件

    应用场景与问题 当项目在运行时,我们如果需要修改log4j 1.X或者log4j2的配置文件,一般来说我们是不能直接将项目停止运行再来修改文件重新部署的.于是就有这样一个问题:如何在不停止当前项目的运 ...

  5. python 函数求两个数的最大公约数和最小公倍数

    1. 求最小公倍数的算法: 最小公倍数  =  两个整数的乘积 /  最大公约数 所以我们首先要求出两个整数的最大公约数, 求两个数的最大公约数思路如下: 2. 求最大公约数算法: 1. 整数A对整数 ...

  6. Centos 7.x 安装 MongoDB

    官方安装资料:点击直达 本次以Centos为安装主机 1:首先先导入MongoDB的yum源,因为Centos默认是没有MongoDB的yum源,创建文件:/etc/yum.repos.d/mongo ...

  7. [題解](最小生成樹/LCA)luogu_P1967貨車運輸

    一道好題不出所料又抄的題解 1.首先對於這張圖肯定要考慮走哪些邊不走哪些邊,發現我們想要的肯定那些邊權最大的邊,所以想到最大生成樹 這樣能保證選到盡量大的邊 2.跑完最大生成樹后每兩點之間就有唯一路徑 ...

  8. 使用CSS 实现菱形图片,斜条纹背景

    比较简单的菱形图片: 效果如下 代码部分: <div class="d1"> <img src="img/5.jpg"> </di ...

  9. 洛谷1280(dp)

    题目性质:1.当前节点空闲则必须做任务,而不是可选可不选:2.然而前面的如果能覆盖当前节点,就可以不选. 解决方法:倒着扫可以很好地解决这两个问题.dp[i]为时刻i可得的最大空闲时间.如果此刻没有任 ...

  10. 洛谷 P1121 环状最大两段子段和

    https://www.luogu.org/problemnew/show/P1121 不会做啊... 看题解讲的: 答案的两段可能有两种情况:一是同时包含第1和第n个,2是不同时包含第1和第n个 对 ...