图论$\cdot$2-SAT问题
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问题的更多相关文章
- 多边形碰撞 -- SAT方法
检测凸多边形碰撞的一种简单的方法是SAT(Separating Axis Theorem),即分离轴定理. 原理:将多边形投影到一条向量上,看这两个多边形的投影是否重叠.如果不重叠,则认为这两个多边形 ...
- 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 ...
- Map Labeler POJ - 2296(2 - sat 具体关系建边)
题意: 给出n个点 让求这n个点所能建成的正方形的最大边长,要求不覆盖,且这n个点在正方形上或下边的中点位置 解析: 当然是二分,但建图就有点还行..比较难想..行吧...我太垃圾... 2 - s ...
- python数据结构之图论
本篇学习笔记内容为图的各项性质.图的表示方法.图ADT的python实现 图(Graph) 是数据结构和算法学中最强大的框架之一(或许没有之一).图几乎可以用来表现所有类型的结构或系统,从交通网络到通 ...
- 学习笔记(two sat)
关于two sat算法 两篇很好的论文由对称性解2-SAT问题(伍昱), 赵爽 2-sat解法浅析(pdf). 一些题目的题解 poj 3207 poj 3678 poj 3683 poj 3648 ...
- LA 3211 飞机调度(2—SAT)
https://vjudge.net/problem/UVALive-3211 题意: 有n架飞机需要着陆,每架飞机都可以选择“早着陆”和“晚着陆”两种方式之一,且必须选择一种,第i架飞机的早着陆时间 ...
- HIT 1917 2—SAT
题目大意:一国有n个党派,每个党派在议会中都有2个代表, 现要组建和平委员会,要从每个党派在议会的代表中选出1人,一共n人组成和平委员会. 已知有一些代表之间存在仇恨,也就是说他们不能同时被选为和平委 ...
- 2 - sat 模板(自用)
2-sat一个变量两种状态符合条件的状态建边找强连通,两两成立1 - n 为第一状态(n + 1) - (n + n) 为第二状态 例题模板 链接一 POJ 3207 Ikki's Story IV ...
- SAT考试里最难的数学题? · 三只猫的温暖
问题 今天无意中在Quora上看到有人贴出来一道号称是SAT里最难的一道数学题,一下子勾起了我的兴趣.于是拿起笔来写写画画,花了差不多十五分钟搞定.觉得有点意思,决定把解题过程记下来.原帖的图太小,我 ...
- 世界碰撞算法原理和总结(sat gjk)
序言 此文出于作者的想法,从各处文章和论文中,总结和设计项目中碰撞结构处理方法.如有其它见解,可以跟作者商讨.(杨子剑,zijian_yang@yeah.net). 在一个世界中,有多个物体,物体可以 ...
随机推荐
- javascript平时小例子③(setInterval使用1)
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- JQ 队列
<div class="divtt"> <div class="divtest"></div> </div> & ...
- Android错误:W/ResourceType(2411): No package identifier when getting value for resource number 0x
报错信息: 07-04 11:14:43.064: W/ResourceType(2411): No package identifier when getting value for resourc ...
- oracle函数,查询,事务
函数包括:单行函数,多行函数(分组函数) 数值函数: --绝对值 select abs(-12.3) from dual; --向上取值 select ceil(5.3) from dual; --向 ...
- IOS第七天(6:UiTableView编辑模式, 拖动位置 ,滑动删除)
**********UiTableView编辑模式, 拖动位置 ,滑动删除 #import "HMViewController.h" @interface HMViewContro ...
- php SPL学习
数据结构 SplDoublyLinkedList - 该SplDoublyLinkedList类提供了一个双向链表的主要功能 SplStack - 该SplStack类提供了一种使用双向链表实现栈的主 ...
- php 生成唯一id的几种解决方法
php 生成唯一id的几种解决方法 网上查了下,有很多的方法 1.md5(time() . mt_rand(1,1000000)); 这种方法有一定的概率会出现重复 2.php内置函数uniqid ...
- C#的TreeView标记
今天用到了TreeView控件,多次添加后发现内容是重复的,于是用到清除:this.myTreeView.Nodes.Clear(): 如果想在添加完节点后,默认全展开:this.myTreeView ...
- xib连线出错,模型保存cell状态(最后个Cell隐藏分割线),
一个.m文件中有好几个cell类,拖线,要看看该控件对应的是哪个类,否则点击事件不响应,因为归属的xib错了 拖不过来线,因为是view拖不动,加了个button就行了 使用模型属性记录是否隐藏c ...
- [转]Haroopad Markdown 编辑器代码语法高亮支持
代码语法高亮 书写格式为: ` ` ` language_key if (condition){ return true } ` ` ` 在 ` ` ` (三个反引号)之间的是代码,其中languag ...