讨论2-sat建设和解决问题
2-sat问题是一种常见的问题。给定若干个01变量,变量之间满足一些二元约束,求是否有解存在。若存在,给出可行解或依照字典序给出最优解。
以下给出与其相应的图论模型:给每一个变量i设立2个点,我的习惯是记为T(i),F(i),分别表示其值取1,0.
以下考虑的便是怎样进行限制了。
一般的限制形式均例如以下所看到的:
变量i取x时,变量j仅仅能取y,那么表示i取x的点向表示j取y的点连一条有向边。表示推出关系。
类似的,若表示变量i取x时,变量j不能取y,那么表示i取x的点向表示j取~y的点连一条有向边。由于每一个变量必然有值,且仅仅有一个值。
以上这些限制每次都须要连两条边,即原命题和其逆否命题。
有一些另外的限制比較特殊:即变量i仅仅能取x,那么表示i取~x的点向表示i取x的点连一条有向边.若表示变量i不能取x,那么表示i取x的点向表示i取~x的点连一条有向边.这些限制仅仅连一条边。
接下来,利用Tarjan算法求解强联通分量,若表示某个变量为0的点和表示这个变量为1的点在同一个强联通分量中,表示存在矛盾,2-sat问题无解。
以下看一下怎样求出一组可行解。
我们构造求出的DAG的反图,按照拓扑序依次进行处理。对于当前点,若没有被染色,则染色为1,并将这个连通分量中全部点的还有一个解所相应的点所在的分量及其子孙均染色为2.(注意,这是在反图中。)染色就递归去染就好了,当遇到一个已经被染色为2的点就不向下染色了。
那么终于每一个变量的解就是被染色为1的分量所包括的该变量所相应的解。
以下来看几道题:
POJ3207
Sol:以这条边在圈内作为0,在圈外作为1,限制就是假设两条边区间相交,那么值不能同样。那么T(i)->F(j),T(j)->F(i).仅仅需推断这个2-sat问题是否有解就可以。
Code:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <algorithm>
using namespace std; #define N 510
int l[N], r[N]; int head[N << 1], next[N * N << 2], end[N * N << 2];
void addedge(int a, int b) {
static int q = 1;
end[q] = b;
next[q] = head[a];
head[a] = q++;
} #define T(i) (i << 1)
#define F(i) ((i << 1) | 1) int dfn[N << 1], low[N << 1], tclock, stack[N << 1], top, belong[N << 1], num;
bool instack[N << 1]; void dfs(int x) {
dfn[x] = low[x] = ++tclock;
stack[++top] = x;
instack[x] = 1;
for(int j = head[x]; j; j = next[j]) {
if (!dfn[end[j]])
dfs(end[j]), low[x] = min(low[x], low[end[j]]);
else if (instack[end[j]])
low[x] = min(low[x], dfn[end[j]]);
}
if (low[x] == dfn[x]) {
++num;
while(1) {
int i = stack[top--];
belong[i] = num;
instack[i] = 0;
if (i == x)
break;
}
}
} int main() {
int n, m;
scanf("%d%d", &n, &m); register int i, j;
int a, b;
for(i = 1; i <= m; ++i) {
scanf("%d%d", &a, &b);
l[i] = ++a;
r[i] = ++b;
if (l[i] > r[i])
swap(l[i], r[i]);
} for(i = 1; i <= m; ++i) {
for(j = i + 1; j <= m; ++j) {
if (l[j] > l[i] && l[j] < r[i] && r[j] > r[i]) {
addedge(T(i), F(j));
addedge(F(i), T(j));
addedge(T(j), F(i));
addedge(F(j), T(i));
}
}
} for(i = T(1); i <= F(m); ++i)
if (!dfn[i])
dfs(i); bool find = 0;
for(i = 1; i <= m; ++i)
if (belong[T(i)] == belong[F(i)]) {
find = 1;
break;
} if (find)
puts("the evil panda is lying again");
else
puts("panda is telling the truth..."); return 0;
}
BZOJ1997
Sol:基本和上道题类似。也仅仅须要推断是否有解。
Code:
#include <cctype>
#include <cstdio>
#include <cstring>
#include <climits>
#include <algorithm>
using namespace std; inline int getc() {
static const int L = 1 << 15;
static char buf[L], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, L, stdin);
if (S == T)
return EOF;
}
return *S++;
}
inline int getint() {
int c;
while(!isdigit(c = getc()));
int tmp = c - '0';
while(isdigit(c = getc()))
tmp = (tmp << 1) + (tmp << 3) + c - '0';
return tmp;
} #define N 210
#define M 10010
int hash[N]; struct Edge {
int f, t;
Edge(int _f = 0, int _t = 0):f(_f),t(_t){}
}E[M], sav[M];
int top; struct Graph {
int head[1210], next[819200], end[819200], ind;
int dfn[1210], low[1210], tclock, stack[1210], top, belong[1210], cnt;
bool instack[1210];
void reset() {
ind = tclock = top = cnt = 0;
memset(head, -1, sizeof(head));
memset(dfn, 0, sizeof(dfn));
}
void addedge(int a, int b) {
int q = ind++;
end[q] = b;
next[q] = head[a];
head[a] = q;
}
void dfs(int x) {
dfn[x] = low[x] = ++tclock;
instack[x] = 1;
stack[++top] = x;
for(int j = head[x]; j != -1; j = next[j]) {
if (!dfn[end[j]]) {
dfs(end[j]);
low[x] = min(low[x], low[end[j]]);
}
else if (instack[end[j]])
low[x] = min(low[x], dfn[end[j]]);
}
if (low[x] == dfn[x]) {
++cnt;
while(1) {
int i = stack[top--];
belong[i] = cnt;
instack[i] = 0;
if (x == i)
break;
}
}
}
}G; #define T(i) (i * 2 - 2)
#define F(i) (i * 2 - 1) inline bool is_intersect(int i, int j) {
return sav[j].f > sav[i].f && sav[j].f < sav[i].t && sav[j].t > sav[i].t;
} int main() {
int T = getint(); register int i, j;
int n, m;
while(T--) {
n = getint(), m = getint();
for(i = 1; i <= m; ++i)
E[i].f = getint(), E[i].t = getint();
int x;
for(i = 1; i <= n; ++i) {
x = getint();
hash[x] = i;
} if (m > 3 * n + 6) {
puts("NO");
continue;
} top = 0;
int f, t;
for(i = 1; i <= m; ++i) {
f = hash[E[i].f], t = hash[E[i].t];
if (f > t)
swap(f, t);
if (!((f + 1 == t) || (f == 1 && t == n))) {
sav[++top] = Edge(f, t);
}
} G.reset();
for(i = 1; i <= top; ++i) {
for(j = i + 1; j <= top; ++j) {
if (is_intersect(i, j) || is_intersect(j, i)) {
G.addedge(T(i), F(j));
G.addedge(F(i), T(j));
G.addedge(T(j), F(i));
G.addedge(F(j), T(i));
}
}
} for(i = T(1); i <= F(top); ++i)
if (!G.dfn[i])
G.dfs(i); bool find = 0;
for(i = 1; i <= top; ++i)
if (G.belong[T(i)] == G.belong[F(i)]) {
find = 1;
break;
} if (find)
puts("NO");
else
puts("YES");
} return 0;
}
POJ3678
Sol:一堆乱七八糟的位运算。。。涉及到某变量强制取值的建模技巧。仅仅需推断是否有解。
Code:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <algorithm>
using namespace std; #define N 1010
#define M 1000010
int head[N << 1], end[M << 2], next[M << 2];
void addedge(int a, int b) {
static int q = 1;
end[q] = b;
next[q] = head[a];
head[a] = q++;
} #define T(i) (i << 1)
#define F(i) ((i << 1) | 1) int dfn[N << 1], low[N << 1], tclock, stack[N << 1], top, belong[N << 1], num;
bool instack[N << 1];
void dfs(int x) {
dfn[x] = low[x] = ++tclock;
stack[++top] = x;
instack[x] = 1;
for(int j = head[x]; j; j = next[j]) {
if (!dfn[end[j]]) {
dfs(end[j]);
low[x] = min(low[x], low[end[j]]);
}
else if (instack[end[j]])
low[x] = min(low[x], dfn[end[j]]);
}
if (dfn[x] == low[x]) {
++num;
while(1) {
int i = stack[top--];
belong[i] = num;
instack[i] = 0;
if (i == x)
break;
}
}
} int main() {
int n, m;
scanf("%d%d", &n, &m); register int i;
char s[10];
int a, b, x; for(i = 1; i <= m; ++i) {
scanf("%d%d%d%s", &a, &b, &x, s);
++a, ++b;
if (s[0] == 'A') {
if (x) {
addedge(F(a), T(a));
addedge(F(b), T(b));
}
else {
addedge(T(a), F(b));
addedge(T(b), F(a));
}
}
if (s[0] == 'O') {
if (x) {
addedge(F(a), T(b));
addedge(F(b), T(a));
}
else {
addedge(T(a), F(a));
addedge(T(b), F(b));
}
}
if (s[0] == 'X') {
if (x) {
addedge(T(a), F(b));
addedge(F(a), T(b));
addedge(T(b), F(a));
addedge(F(b), T(a));
}
else {
addedge(T(a), T(b));
addedge(F(a), F(b));
addedge(T(b), T(a));
addedge(F(b), F(a));
}
}
} for(i = T(1); i <= F(n); ++i)
if (!dfn[i])
dfs(i); bool find = 0;
for(i = 1; i <= n; ++i) {
if (belong[T(i)] == belong[F(i)]) {
find = 1;
break;
}
} if (find)
puts("NO");
else
puts("YES"); return 0;
}
POJ3683
Sol:每一个婚礼分为是开头还是结尾作为01取值,建模非常easy,若区间相交则矛盾就可以。
比較锻炼代码能力的一道题。。。
Code:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cctype>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std; #define N 1010
int l[N], r[N], len[N]; int get(char *s) {
return 600*(s[0]-'0')+60*(s[1]-'0')+10*(s[3]-'0')+(s[4]-'0');
} int head[N << 1], next[N * N << 3], end[N * N << 3];
void addedge(int a, int b) {
static int q = 1;
end[q] = b;
next[q] = head[a];
head[a] = q++;
} #define T(i) (i << 1)
#define F(i) ((i << 1) | 1) int dfn[N << 1], low[N << 1], tclock, stack[N << 1], top, belong[N << 1], num;
vector<int> sav[N << 1];
bool instack[N << 1];
void dfs(int x) {
dfn[x] = low[x] = ++tclock;
stack[++top] = x;
instack[x] = 1;
for(int j = head[x]; j; j = next[j]) {
if (!dfn[end[j]]) {
dfs(end[j]);
low[x] = min(low[x], low[end[j]]);
}
else if (instack[end[j]])
low[x] = min(low[x], dfn[end[j]]);
}
if (dfn[x] == low[x]) {
++num;
while(1) {
int i = stack[top--];
instack[i] = 0;
belong[i] = num;
sav[num].push_back(i);
if (x == i)
break;
}
}
} queue<int> q;
struct Graph {
int head[N << 1], next[N * N << 3], end[N * N << 3], in[N << 1], ind, col[N << 1];
void reset() {
ind = 0;
memset(head, -1, sizeof(head));
}
void addedge(int a, int b) {
int q = ind++;
end[q] = b;
next[q] = head[a];
head[a] = q;
++in[b];
}
void Paint(int x) {
col[x] = 2;
for(int j = head[x]; j != -1; j = next[j])
if (col[end[j]] != 2)
Paint(end[j]);
}
void TopoSort() {
int i, j;
for(i = 1; i <= num; ++i)
if (!in[i])
q.push(i);
while(!q.empty()) {
i = q.front();
q.pop();
if (!col[i]) {
col[i] = 1;
int size = sav[i].size();
for(j = 0; j < size; ++j)
Paint(belong[sav[i][j] ^ 1]);
}
for(j = head[i]; j != -1; j = next[j])
if (!--in[end[j]])
q.push(end[j]);
}
}
}G; bool isnot_insect(int l1, int r1, int l2, int r2) {
return r1 <= l2 || r2 <= l1;
} void print(int x) {
int t = x % 60;
printf("%02d:%02d", (x - t) / 60, t);
} int main() {
int n;
scanf("%d", &n); char s1[10], s2[10];
int i, j; for(i = 1; i <= n; ++i) {
scanf("%s%s%d", s1, s2, &len[i]);
l[i] = get(s1);
r[i] = get(s2);
} for(i = 1; i <= n; ++i) {
for(j = i + 1; j <= n; ++j) {
if (!isnot_insect(l[i], l[i] + len[i], l[j], l[j] + len[j])) {
addedge(T(i), F(j));
addedge(T(j), F(i));
}
if (!isnot_insect(l[i], l[i] + len[i], r[j] - len[j], r[j])) {
addedge(T(i), T(j));
addedge(F(j), F(i));
}
if (!isnot_insect(r[i] - len[i], r[i], l[j], l[j] + len[j])) {
addedge(F(i), F(j));
addedge(T(j), T(i));
}
if (!isnot_insect(r[i] - len[i], r[i], r[j] - len[j], r[j])) {
addedge(F(i), T(j));
addedge(F(j), T(i));
}
}
} for(i = T(1); i <= F(n); ++i)
if (!dfn[i])
dfs(i); bool find = 0;
for(i = 1; i <= n; ++i)
if (belong[T(i)] == belong[F(i)]) {
find = 1;
break;
} if (find) {
puts("NO");
return 0;
} G.reset();
for(i = T(1); i <= F(n); ++i)
for(j = head[i]; j; j = next[j])
if (belong[i] != belong[end[j]])
G.addedge(belong[end[j]], belong[i]);
G.TopoSort();
puts("YES");
for(i = 1; i <= n; ++i) {
if (G.col[belong[T(i)]] == 1)
print(l[i]), putchar(' '), print(l[i] + len[i]);
else
print(r[i] - len[i]), putchar(' '), print(r[i]);
puts("");
} return 0;
}
BZOJ1823
Sol:十分的裸题。。。
Code:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <algorithm>
using namespace std; #define N 110
#define M 1010
struct Graph {
int head[N << 1], next[M << 1], end[M << 1], ind;
int dfn[N << 1], low[N << 1], tclock, stack[N << 1], top, belong[N << 1], num;
bool instack[N << 1];
void reset() {
ind = tclock = top = num = 0;
memset(dfn, 0, sizeof(dfn));
memset(head, -1, sizeof(head));
}
void addedge(int a, int b) {
int q = ind++;
end[q] = b;
next[q] = head[a];
head[a] = q;
}
void dfs(int x) {
dfn[x] = low[x] = ++tclock;
instack[x] = 1;
stack[++top] = x;
for(int j = head[x]; j != -1; j = next[j]) {
if (!dfn[end[j]]) {
dfs(end[j]);
low[x] = min(low[x], low[end[j]]);
}
else if (instack[end[j]])
low[x] = min(low[x], dfn[end[j]]);
}
if (dfn[x] == low[x]) {
++num;
while(1) {
int i = stack[top--];
belong[i] = num;
instack[i] = 0;
if (x == i)
break;
}
}
}
}G; #define T(i) (i << 1)
#define F(i) ((i << 1) | 1) int getint(char *s) {
int len = strlen(s);
int res = 0;
for(int i = 1; i < len; ++i)
res = (res << 3) + (res << 1) + s[i] - '0';
return res;
} int main() {
int Case;
scanf("%d", &Case); int n, m;
char s1[60], s2[60];
register int i, j;
bool b1, b2;
int n1, n2; while(Case--) {
G.reset(); scanf("%d%d", &n, &m);
for(i = 1; i <= m; ++i) {
scanf("%s%s", s1, s2);
b1 = (s1[0] == 'm');
b2 = (s2[0] == 'm');
n1 = getint(s1);
n2 = getint(s2);
if (b1 && b2)
G.addedge(F(n1), T(n2)), G.addedge(F(n2), T(n1));
if (b1 && !b2)
G.addedge(F(n1), F(n2)), G.addedge(T(n2), T(n1));
if (!b1 && b2)
G.addedge(T(n1), T(n2)), G.addedge(F(n2), F(n1));
if (!b1 && !b2)
G.addedge(T(n1), F(n2)), G.addedge(T(n2), F(n1));
} for(i = T(1); i <= F(n); ++i)
if (!G.dfn[i])
G.dfs(i); bool find = 0;
for(i = 1; i <= n; ++i)
if (G.belong[T(i)] == G.belong[F(i)]) {
find = 1;
break;
}
if (find)
puts("BAD");
else
puts("GOOD");
} return 0;
}
就到这里结束怎样?
讨论2-sat建设和解决问题的更多相关文章
- PMP学习笔记
PMI:Project Management Institute,项目管理协会于1969年在美国成立,致力于全球范围内的项目管理研究.标准制定和出版.价值倡导.职业认证和学位 课程认证.现在,PMI已 ...
- DeviceOne接受了DevStore的专访
DevStore隶属深圳尺子科技有限公司,DevStore所有内容(资讯.数据.工具|服务.资源文章.问答……)都贯穿整个项目的生命周期,无论你是设计人员.开发人员.推广人员还是运营人员都可在此找到你 ...
- NABCD模型进行竞争性需求分析
确定项目:教室管理系统 负责人:李凤娇,高德建 选择比努力更重要.一个项目成功自然离不开组员们的努力.但是,光努力是不够的.还需要用户有需求,能快速实现. 这些东西,看似很虚,却能让我们少走不少弯路. ...
- 记一个由MemCached引发的性能问题
最近有个项目用loadrunner做了压力测试,发现并发量还不到200服务器就支撑不住了.boss那边紧急开会,说此项目最近3个月内将有100家中大型公司用于校园招聘工作,如果这个问题不解决公司有可能 ...
- Beta版本展示
Beta版本展示 开发团队:MyGod 团队成员:程环宇 张芷祎 王田路 张宇光 王婷婷 源码地址:https://github.com/WHUSE2017/MyGod MyGod团队项目的目标: 让 ...
- C语言作业程序设计第一次作业
1.求圆面积和面积 (1)题目: 输入圆的半径,计算圆的周长和面积 (2)流程图: (3)测试数据及运行结果 测试数据:r=4 运行结果: (4)实验分析 没有遇到问题 2.判断闰年问题 (1)题目: ...
- 2丶利用NABCD模型进行竞争性需求分析
确定项目:公交查询系统 分析小组:在路上 选择比努力更重要.一个项目成功自然离不开组员们的努力.但是,光努力是不够的.还需要用户有需求,能快速实现. 这些东西,看似很虚,却能让我们少走不少弯路.做项目 ...
- Team抢救最后一下
Team抢救最后一下 Task1:Team抢救的总结 秦玉: 非常荣幸能以团队的方式获得这次的小黄衫,这件衣服的意义不仅是这门课的奖励,也会是我们整个抢救团队的一个见证和回忆~ ...
- 福大软工 Alpha 事后诸葛亮
写在前面 林燊大哥 一路走来,好不容易,终于完结了. 设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 解决的问题 用户在进店之前无法得知店铺的优劣 ...
随机推荐
- 快速杀死占用8080端口进程的批处理(kill-8080.bat)
@echo off setlocal enabledelayedexpansion for /f "delims= tokens=1" %%i in ('netstat -aon ...
- POJ 1887 Testing the CATCHER(LIS的反面 最大递减子序列)
Language: Default Testing the CATCHER Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 1 ...
- 如何知道刚刚插入数据库那条数据的id
如何知道刚刚插入数据库那条数据的id 一.总结 一句话总结:这些常见功能各个框架里面都有,可以查看手册,thinkphp里面是$userId = Db::name('user')->getLas ...
- udacity android 实践笔记: lesson 4 part a
udacity android 实践笔记: lesson 4 part a 作者:干货店打杂的 /titer1 /Archimedes 出处:https://code.csdn.net/titer1 ...
- Hadoop基本原理之一:MapReduce 分类: A1_HADOOP 2014-08-17 19:26 1113人阅读 评论(0) 收藏
1.为什么需要Hadoop 目前,一块硬盘容量约为1TB,读取速度约为100M/S,因此完成一块硬盘的读取需时约2.5小时(写入时间更长).若把数据放在同一硬盘上,且全部数据均需要同一个程序进行处理, ...
- html js 上传图片 预览
第一段代码是我自己修改之后能够多选显示多预览图,也就是加了个循环,后面的代码是一些解释说明之类的,抄的 <!DOCTYPE html> <html> <head> ...
- [Jenkins] Define a pipeline
node{ stage 'checkout' git '[github_url]' def project_path="[project_path]" // everythin i ...
- 关于如何在Sublime下安装插件
安装插件的两种方式 通过Package Control安装 不能安装 手工安装 安装插件的两种方式 在sublime下安装插件有两种方式,一种是通过package control来进行安装,另一种呢就 ...
- [tmux] Organize your terminal using tmux panes
Learn to organize your workspace using tmux. We'll create a new tmux session and learn how to create ...
- 【t061】游览路线
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 话说LCINF信息组来到烟台参加夏令营.一天,大家提议出去游玩,来到了烟台最繁华的地方.由于他们对烟台 ...