2-SAT问题是这样的:有$n$个布尔变量$x_i$,另有$m$个需要满足的条件,每个条件的形式都是“$x_i$为真/假或者$x_j$为真/假”。比如:"$x_1$为真或者$x_3$为假“。注意这里的”或“是指两个条件至少有一个是正确的,比如$x_1$和$x_3$一共有$3$中组合满足"$x_1$为真或者$x_3$为假“。2-SAT问题的目标是给每个变量赋值,使得所有条件得到满足。求解2-SAT问题一般比较常见方法是构造一张有向图$G$,其中每个变量$x_i$拆成两个结点$2i$和$2i+1$,分别表示$x_i$为假和$x_i$为真。最后要为每个变量选择其中一个结点标记。比如,若标记了节点$2i$,表示$x_i$为假;如果标记了$2i+1$,表示$x_i$为真。对于“$x_i$为假或者$x_j$为假”这样的条件,我们连一条有向边$2i+1 \rightarrow 2j$,表示如果标记节点$2i+1$那么也必须标记结点$j$,同理还需要连一条有向边$2j+1 \rightarrow 2i$。对于其他情况,也可以类似连边。换句话说,每个条件对应两条“对称”的边。接下来逐一考虑每个没有赋值的变量,设为$x_i$。我们首先假定它为假,然后标记借点$2_i$,并且沿着有向边标记所有能标记的结点。如果标记过程中发现某个变量对应的两个结点都被标记,则“$x_i$为假”这个假定不成立,需要改成“$x_i$为真”,然后重新标记。注意,该算法无回溯过程。如果当前考虑的变量不管赋值为真还是假都会引起矛盾,可以证明整个2-SAT问题无解(即使调整以前赋值的变量也没用)。这是很显然的,每个变量只会影响到关系到该变量的表达式的取值,因此对于未赋值的变量一定与之前的赋值无关,可以分开考虑,整个问题有解需要满足每个块都有解。下面给出求解2-SAT问题的代码:

 struct _2_sat{
int n;
vector<int> G[maxn << ];
bool mark[maxn << ];
int S[maxn << ], c;
bool dfs(int x){
if(mark[x ^ ]) return ;
if(mark[x]) return ;
mark[x] = ;
S[c++] = x;
FOR(i, , G[x].size() - ) if(!dfs(G[x][i])) return ;
return ;
}
void init(int n){
this->n = n;
FOR(i, , * n - ) G[i].clear();
clr(mark, );
}
//x = xval or y = yval
void add_caluse(int x, int xval, int y, int yval){
x = x * + xval, y = y * + yval;
G[x ^ ].pb(y), G[y ^ ].pb(x);
}
bool solve(){
for(int i = ; i < * n; i += ) if(!mark[i] && !mark[i + ]){
c = ;
if(!dfs(i)){
while(c > ) mark[S[--c]] = ;
if(!dfs(i + )) return ;
}
}
return ;
}
};

相关习题:

LA 3713 Astronauts

 #include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <ctime>
#include <cmath>
#include <iostream>
#include <assert.h>
#pragma comment(linker, "/STACK:102400000,102400000")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define mp std :: make_pair
#define st first
#define nd second
#define keyn (root->ch[1]->ch[0])
#define lson (u << 1)
#define rson (u << 1 | 1)
#define pii std :: pair<int, int>
#define pll pair<ll, ll>
#define pb push_back
#define type(x) __typeof(x.begin())
#define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++)
#define FOR(i, s, t) for(int i = (s); i <= (t); i++)
#define ROF(i, t, s) for(int i = (t); i >= (s); i--)
#define dbg(x) std::cout << x << std::endl
#define dbg2(x, y) std::cout << x << " " << y << std::endl
#define clr(x, i) memset(x, (i), sizeof(x))
#define maximize(x, y) x = max((x), (y))
#define minimize(x, y) x = min((x), (y))
using namespace std;
typedef long long ll;
const int int_inf = 0x3f3f3f3f;
const ll ll_inf = 0x3f3f3f3f3f3f3f3f;
const int INT_INF = (int)((1ll << ) - );
const double double_inf = 1e30;
const double eps = 1e-;
typedef unsigned long long ul;
typedef unsigned int ui;
inline int readint(){
int x;
scanf("%d", &x);
return x;
}
inline int readstr(char *s){
scanf("%s", s);
return strlen(s);
} class cmpt{
public:
bool operator () (const int &x, const int &y) const{
return x > y;
}
}; int Rand(int x, int o){
//if o set, return [1, x], else return [0, x - 1]
if(!x) return ;
int tem = (int)((double)rand() / RAND_MAX * x) % x;
return o ? tem + : tem;
}
ll ll_rand(ll x, int o){
if(!x) return ;
ll tem = (ll)((double)rand() / RAND_MAX * x) % x;
return o ? tem + : tem;
} void data_gen(){
srand(time());
freopen("in.txt", "w", stdout);
int kases = ;
printf("%d\n", kases);
while(kases--){
ll sz = ;
printf("%d\n", sz);
FOR(i, , sz){
int o = Rand(, );
int x = Rand(1e9, );
int y1 = Rand(1e9, ), y2 = Rand(1e9, );
if(o == ) printf("%d %d %d %d\n", x, y1, x, y1);
else printf("%d %d %d %d\n", y1, x, y2, x);
}
}
}
const int maxn = 1e5 + ;
int n, m;
ll sum;
int id[maxn];
int age[maxn];
int head[maxn << ];
struct E{
int to, nex;
}e[maxn << ];
bool vis[maxn << ];
int N;
void addE(int x, int y){
e[N].nex = head[x];
e[N].to = y;
head[x] = N++;
}
int stk[maxn], k;
bool dfs(int u){
if(vis[u]) return ;
vis[u] = ;
stk[k++] = u;
if(vis[u] && vis[u ^ ]) return ;
for(int i = head[u]; ~i; i = e[i].nex){
int v = e[i].to;
if(!dfs(v)) return ;
}
return ;
} bool solve(int u){
k = ;
if(dfs( * u)) return ;
while(k) vis[stk[--k]] = ;
if(dfs( * u + )) return ;
return ;
} int main(){
//data_gen(); return 0;
//C(); return 0;
int debug = ;
if(debug) freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
while(~scanf("%d%d", &n, &m) && n){
sum = ;
FOR(i, , n - ) age[i] = readint(), sum += age[i];
FOR(i, , n - ) id[i] = (ll)age[i] * n >= sum ? : ;
clr(head, -), N = ;
FOR(i, , m - ){
int x = readint() - , y = readint() - ;
//cc[i][0] = x, cc[i][1] = y;
addE( * x, * y + );
if(id[x] == id[y]) addE( * x + , * y);
addE( * y, * x + );
if(id[x] == id[y]) addE( * y + , * x);
}
int ok = ;
clr(vis, );
FOR(i, , n - ) if(!vis[ * i] && !vis[ * i + ] && !solve(i)){
ok = ;
break;
}
if(!ok) puts("No solution.");
else FOR(i, , n - ) putchar(!vis[ * i + ] ? 'C' : 'A' + id[i]), putchar('\n');
//int res = verdict();
//printf("verdict :: %s", res ? "ok\n" : "err\n");
}
return ;
}

code:

图论$\cdot$2-SAT问题的更多相关文章

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

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

  2. 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 ...

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

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

  4. python数据结构之图论

    本篇学习笔记内容为图的各项性质.图的表示方法.图ADT的python实现 图(Graph) 是数据结构和算法学中最强大的框架之一(或许没有之一).图几乎可以用来表现所有类型的结构或系统,从交通网络到通 ...

  5. 学习笔记(two sat)

    关于two sat算法 两篇很好的论文由对称性解2-SAT问题(伍昱), 赵爽 2-sat解法浅析(pdf). 一些题目的题解 poj 3207 poj 3678 poj 3683 poj 3648 ...

  6. LA 3211 飞机调度(2—SAT)

    https://vjudge.net/problem/UVALive-3211 题意: 有n架飞机需要着陆,每架飞机都可以选择“早着陆”和“晚着陆”两种方式之一,且必须选择一种,第i架飞机的早着陆时间 ...

  7. HIT 1917 2—SAT

    题目大意:一国有n个党派,每个党派在议会中都有2个代表, 现要组建和平委员会,要从每个党派在议会的代表中选出1人,一共n人组成和平委员会. 已知有一些代表之间存在仇恨,也就是说他们不能同时被选为和平委 ...

  8. 2 - sat 模板(自用)

    2-sat一个变量两种状态符合条件的状态建边找强连通,两两成立1 - n 为第一状态(n + 1) - (n + n) 为第二状态 例题模板 链接一  POJ 3207 Ikki's Story IV ...

  9. SAT考试里最难的数学题? · 三只猫的温暖

    问题 今天无意中在Quora上看到有人贴出来一道号称是SAT里最难的一道数学题,一下子勾起了我的兴趣.于是拿起笔来写写画画,花了差不多十五分钟搞定.觉得有点意思,决定把解题过程记下来.原帖的图太小,我 ...

  10. 世界碰撞算法原理和总结(sat gjk)

    序言 此文出于作者的想法,从各处文章和论文中,总结和设计项目中碰撞结构处理方法.如有其它见解,可以跟作者商讨.(杨子剑,zijian_yang@yeah.net). 在一个世界中,有多个物体,物体可以 ...

随机推荐

  1. javaweb实验五

    product类: package com.lab;public class Product { private int id;                // 商品编号    private S ...

  2. 调试WEB APP多设备浏览器

    方法:adobe shadow  \ opera远程调试\ weinre adobe shadow: 我们经常使用Firefox的firebug或者Chrome的开发人员工具进行Web调试页面,Jav ...

  3. window svn backup.bat

    help command /? call /? %cd% 可以用在批处理文件中,也可以用在命令行中:展开后,是驱动器盘符:+当前目录,如在dos窗口中进入c:\dir目录下面, %0代指批处理文件自身 ...

  4. 微信公众号内H5调用微信支付国内服务商模式

    最近在折微信公众号内H5用JSAPI调用微信支付,境内服务商版支付,微信支付给出的官方文档以及SDK不够详细,导至我们走了一些弯路,把他分享出来,我这边主要是用PHP开发,所以未加说的话示例都是PHP ...

  5. Eclipse序列号生成代码

    import java.io.*; public class MyEclipseGen { private static final String LL = "Decompiling thi ...

  6. Python开发问题和解决方案汇集

    1.Sublime Text中用Tab批量替换空格Whitespace缩进:Ctrl+A全选代码,Ctrl+Shift+P打开下拉框,输入indent,找到Convert indentation to ...

  7. Vim配置文件备忘

    "我的配置 """""""""其他"""""&qu ...

  8. Thinking in Java——笔记(9)

    Polymorphism Abstract classes and methods If you have an abstract class, objects of that specific cl ...

  9. 类似网易新闻 title栏 滚动时 文字放大&变色

    http://files.cnblogs.com/files/n1ckyxu/ScrollTitleView.zip

  10. Java初始化生命周期

    package com.init; abstract class Glyph { void draw() { System.out.println("Glyph.draw()"); ...