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. 跳转到另一个APP

    看看这个代码: http://code4app.com/codesample/4fcc512d6803fae60b000002 inApp跳转,不过需要Nimbus类库. 要跳转到另一个APP,需要另 ...

  2. go系列(1)- linux下安装go环境

    安装GO 打开安装包下载地址,查看linux下go的最新版本 https://golang.google.cn/dl/ 经查看go的最新版本为go1.11.4.linux-amd64.tar.gz 右 ...

  3. excel输入值非法,限定了可以输入的数值怎么办

    回到excel的编辑界面,点击工具栏的“数据”标签,如图所示. 继续在“数据”标签的下面找到“数据验证”或“数据有效性”的按钮,点击该选项,然后继续下一步. 在弹出的选择框中选择“数据验证”选项,如图 ...

  4. self.navigationController.navigationBar.translucent = YES航栏的属性默认 YES是透明效果并且主view不会偏移 NO是导航栏不透明 主view会向下偏移64px

    交友:微信号 dwjluck2013 从iOS7开始,苹果对navigationBar进行了模糊处理,并把self.navigationController.navigationBar.translu ...

  5. Single-use Stones Codeforces - 965D

    https://codeforces.com/contest/965/problem/D 太神仙了...比E难啊.. 首先呢,根据题意,可以很容易的建出一个最大流模型 就是每个位置建一条边,容量限制为 ...

  6. Hive_Hive的数据类型

    Hive Basic Data Type: Basic Types: tinyint/samllint/int/bigint float/double boolean string Complex T ...

  7. Jmeter(二十三)稳定性测试后的波形图

    jmeter-plugins.org 这个网站为 JMeter 提供了一些增强型功能的插件,使用起来就像 Eclipse 装插件一样,完全做到了插件的可插拔特性.本文简要介绍如何使用这些插件让你的 J ...

  8. Executor等系列概念介绍

    这里对几个常见的的名词进行介绍 Executor 这是个接口,只声明了一个方法—— public interface Executor { void execute(Runnable command) ...

  9. Excel2Json记录

    1.有关配置的读取 import configparser import codecs #配置文件格式[config] #自定义的配置key=valuekey2=value2 读取配置 conf = ...

  10. APPCLOUD 判断网络

    if(api.connectionType == 'none'){ api.toast({ msg : '当前网络不可用,请检查网络设置', duration : , location : 'midd ...