2-Sat小结
关于2-sat,其实就是一些对于每个问题只有两种解,一般会给出问题间的关系,比如and,or,not等关系,判定是否存在解的问题。。
具体看http://blog.csdn.net/jarjingx/article/details/8521690,该博客写得很不错的。
下面是LRJ白书上给的2-sat,个人觉得写的很不错。。效率也很高。
#define maxn 500
struct TwoSat{
int n;
vector<int> G[maxn * ];
bool mark[maxn * ];
int S[maxn * ], c;
bool dfs(int x){ // 搜索一组解
if (mark[x^]) return false; //出现冲突
if (mark[x]) return true;
mark[x] = true;
S[c++] = x;
for (int i = ; i < G[x].size(); ++i)
if (!dfs(G[x][i])) return false;
return true;
} void init(int n){
this->n = n;
for (int i = ; i < * n; ++i)
G[i].clear();
memset(mark, , sizeof(mark));
} void add_clause(int x, int xv, int y, int yv){
x = x * + xv;
y = y * + yv; //x,y不能同时存在,那么如果选了y,合法解必定要选x^1
G[x].push_back(y^1);
G[y].push_back(x^1);
} bool solve(){
for (int i = ; i < n * ; i += )
if (!mark[i] && !mark[i+]){
c = ;
if (!dfs(i)){ //枚举2种取值都无解
while (c > ) mark[S[--c]] = false;
if (!dfs(i+)) return false;
}
}
return true;
}
};
下面是poj上经典2-sat题目:
Poj2296:http://www.cnblogs.com/yzcstc/p/3588099.html
PoJ2723:
题意:
有m道门,每到门上有两把锁,打开其中的一把锁就能打开这道门,有2n把不同的钥匙,每把对应一种锁,这些钥匙被分成n对,每队钥匙只能取其中的一把,取了一把之后另一把就会消失,然后给出每一道门对应的钥匙,求解能打开的门的最大数量.注意,必须打开这一道门才能通往下一个门
思路:
二分一下答案,那么就转化为判定问题。接下去就是2-sat问题了
对于同一对钥匙a和b,属于互斥关系,添加a->~b, b->~a边
对于同一个门的两个钥匙,属于or的 关系,即~a与~b互斥,添加~a->b, ~b->a的边
Code:
/*
* Author: Yzcstc
* Created Time: 2014/3/8 17:14:52
* File Name: Poj2723.cpp
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<ctime>
#define M0(x) memset(x, 0, sizeof(x))
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define red(i, a, b) for (int i = (a); i >= (b); --i)
#define PB push_back
#define Inf 0x3fffffff
#define eps 1e-8
typedef long long LL;
using namespace std;
#define maxn 40000
int p[maxn];
int X[maxn], Y[maxn], n, m, a[maxn], b[maxn];
struct TwoSat{
int n;
vector<int> G[maxn * ];
bool mark[maxn * ];
int S[maxn * ], c;
bool dfs(int x){ // 搜索一组解
if (mark[x^]) return false; //出现冲突
if (mark[x]) return true;
mark[x] = true;
S[c++] = x;
for (int i = ; i < G[x].size(); ++i)
if (!dfs(G[x][i])) return false;
return true;
} void init(int n){
this->n = n;
for (int i = ; i < * n; ++i)
G[i].clear();
memset(mark, , sizeof(mark));
} void add_clause(int x, int xv, int y, int yv){
x = x * + xv;
y = y * + yv; //x,y不能同时存在,那么如果选了y,合法解必定要选x^1
G[x^].push_back(y);
G[y^].push_back(x);
} bool solve(){
for (int i = ; i < n * ; i += )
if (!mark[i] && !mark[i+]){
c = ;
if (!dfs(i)){ //枚举2种取值都无解
while (c > ) mark[S[--c]] = false;
if (!dfs(i+)) return false;
}
}
return true;
}
} S; void init(){
int x, y;
for (int i = ; i < n; ++i){
scanf("%d%d", &x, &y);
X[i] = x;
Y[i] = y;
}
n *= ;
for (int i = ; i <= m; ++i)
scanf("%d%d", &a[i], &b[i]);
} bool check(int floor){
S.init(n);
for (int i = ; i < n / ; ++i){
S.add_clause(X[i], , Y[i], );
// S.add_clause(Y[i], 1, X[i], 1);
}
for (int i = ; i <= floor; ++i){
S.add_clause(a[i], , b[i], );
// S.add_clause(b[i], 0, a[i], 0);
}
return S.solve();
} void solve(){
int l = , r = m, ans = , mid;
while (l <= r){
mid = (l + r) >> ;
if (check(mid)){ans = mid; l = mid + ; }
else r = mid - ;
}
printf("%d\n", ans);
} int main(){
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
while (scanf("%d%d", &n, &m) == && n){
init();
solve();
}
fclose(stdin); fclose(stdout);
return ;
}
Poj2749
题意:
N 个牛栏,现在通过一条通道(s1,s2)把他们连起来,他们之间有一些约束关系,一些牛栏不能连在同一个点,一些牛栏必须连在同一个点,现在问有没有可能把他们都连好,而且满足所有的约束关系,如果可以,输出两个牛栏之间距离最大值的最小情况。
思路:
同样的二分答案。
至于建图:假定对于某个点a,连S1,为事件a,连S2,为事件~a
那么,对于不能连在一起的a, b两点,显然a与b,~a与~b互斥
另外一种情况则反过来。。
还有对于任意a与b,枚举他们的连接情况,一有矛盾同样建边。具体看代码吧
code:
/*
* Author: Yzcstc
* Created Time: 2014/3/12 14:56:50
* File Name: Poj2749.cpp
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<ctime>
#define M0(x) memset(x, 0, sizeof(x))
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define red(i, a, b) for (int i = (a); i >= (b); --i)
#define PB push_back
#define Inf 0x3fffffff
#define eps 1e-8
#define maxn 2000
typedef long long LL;
using namespace std;
struct TwoSat{
int n;
bool mark[maxn];
vector<int> G[maxn];
int S[maxn], c;
bool dfs(int x){
if (mark[x^]) return false;
if (mark[x]) return true;
mark[x] = true;
S[c++] = x;
for (int i = ; i < G[x].size(); ++i)
if (!dfs(G[x][i])) return false;
return true;
} void init(int n){
this->n = n;
for (int i = ; i < * n; ++i) G[i].clear();
memset(mark, , sizeof(mark));
} void add_clause(int x, int xv, int y, int yv){
x = x * + xv;
y = y * + yv;
G[x].push_back(y^);
G[y].push_back(x^);
} bool solve(){
for (int i = ; i < n * ; i += )
if (!mark[i] && !mark[i+]){
c = ;
if (!dfs(i)){
while (c > ) mark[S[--c]] = false;
if (!dfs(i+)) return false;
}
}
return true;
}
} S;
int X[], Y[], F[][], H[][], n, A, B, d[][], dst;
int Sx1, Sx2, Sy1, Sy2; void init(){
scanf("%d%d%d%d", &Sx1, &Sy1, &Sx2, &Sy2);
for (int i = ; i < n; ++i)
scanf("%d%d", &X[i], &Y[i]);
for (int i = ; i < A; ++i)
scanf("%d%d", &H[i][], &H[i][]), --H[i][], --H[i][];
for (int i = ; i < B; ++i)
scanf("%d%d", &F[i][], &F[i][]), --F[i][], --F[i][];
} int dist(int x1, int y1, int x2, int y2){
return abs(x1 - x2) + abs(y1 - y2);
} void get_dist(){
dst = dist(Sx1, Sy1, Sx2, Sy2);
for (int i = ; i < n; ++i){
d[i][] = dist(X[i], Y[i], Sx1, Sy1);
d[i][] = dist(X[i], Y[i], Sx2, Sy2);
}
} bool check(int limit){
S.init(n);
for (int i = ; i < A; ++i){
S.add_clause(H[i][], , H[i][], );
S.add_clause(H[i][], , H[i][], );
}
for (int i = ; i < B; ++i){
S.add_clause(F[i][], , F[i][], );
S.add_clause(F[i][], , F[i][], );
}
int flag = ;
for (int i = ; i < n; ++i)
for (int j = i+; j < n; ++j){
flag = ;
if (d[i][] + d[j][] > limit) { S.add_clause(i, , j, ); flag++; }
if (d[i][] + d[j][] + dst > limit) { S.add_clause(i, , j, ); flag++; }
if (d[i][] + d[j][] + dst > limit) { S.add_clause(i, , j, ); flag++; }
if (d[i][] + d[j][] > limit) { S.add_clause(i, , j, ); flag++; }
if (flag == ) return false;
}
return S.solve();
} void solve(){
get_dist();
int ans = -;
int l = , r = , mid;
while (l <= r){
mid = (l + r) >> ;
if (check(mid)){ans = mid; r = mid - ; }
else l = mid + ;
}
cout << ans << endl;
} int main(){
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
while (scanf("%d%d%d", &n, &A, &B) == ){
init();
solve();
}
fclose(stdin); fclose(stdout);
return ;
}
Poj3207:
题意:
一个圆上有n个点,依次从0到n-1,现在给出m条线段,每条连接两个点,线段可以在圆内也可以在圆外,问能否使得所有线段都不相交。
思路:
简单2-sat。对于两条相交的线段建边。。
code:
/*
* Author: Yzcstc
* Created Time: 2014/3/12 19:09:31
* File Name: poj3207.cpp
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<ctime>
#define M0(x) memset(x, 0, sizeof(x))
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define red(i, a, b) for (int i = (a); i >= (b); --i)
#define PB push_back
#define Inf 0x3fffffff
#define eps 1e-8
#define maxn 2014
typedef long long LL;
using namespace std;
struct TwoSat{
int n;
int S[maxn], c;
bool mark[maxn];
vector<int> G[maxn];
bool dfs(int x){
if (mark[x^]) return false;
if (mark[x]) return true;
mark[x] = true;
S[c++] = x;
for (int i = ; i < G[x].size(); ++i)
if (!dfs(G[x][i])) return false;
return true;
} void init(int n){
this->n = n;
for (int i = ; i < n * ; ++i) G[i].clear();
memset(mark, , sizeof(mark));
} void add_clause(int x, int y){
G[x].push_back(y^);
G[y].push_back(x^);
}
bool solve(){
for (int i = ; i < n * ; i += )
if (!mark[i] && !mark[i+]){
c = ;
if (!dfs(i)){
while (c > ) mark[S[--c]] = false;
if (!dfs(i+)) return false;
}
}
return true;
}
} S;
int m, n, X[], Y[]; bool In(int a, int b, int c){
if (a < b && a < c && c < b) return true;
if (a > b && (c > a || c < b)) return true;
return false;
}
void solve(){
for (int i = ; i < n; ++i)
scanf("%d%d", &X[i], &Y[i]);
S.init(n);
for (int i = ; i < n; ++i)
for (int j = i+; j < n; ++j)
if (In(X[i], Y[i], X[j]) && In(Y[i], X[i], Y[j])
|| In(X[i], Y[i], Y[j]) && In(Y[i], X[i], X[j])){
S.add_clause(i*, j*);
S.add_clause(i*+, j*+);
}
bool ans = S.solve();
if (ans) puts("panda is telling the truth...");
else puts("the evil panda is lying again");
} int main(){
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
while (scanf("%d%d", &m, &n) == ) solve();
fclose(stdin); fclose(stdout);
return ;
}
Poj3648:
题意:
有一对新人结婚,邀请n对夫妇去参加婚礼。有一张很长的桌子,人只能坐在桌子的两边,还要满足下面的要求:1.每对夫妇不能坐在同一侧 2.n对夫妇之中可能有通奸关系(包括男男,男女,女女),有通奸关系的不能同时坐在新娘的对面,可以分开坐,可以同时坐在新娘这一侧。如果存在一种可行的方案,输出与新娘同侧的人。
思路:
算是这几道题比较容易错的了 。
对于x与y通奸,则建x->~y, y->~x的边
而特殊的是新娘要与新郎连一条边,表示坐在对面
code:
/*
* Author: Yzcstc
* Created Time: 2014/3/12 20:08:13
* File Name: poj3468.cpp
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<ctime>
#define M0(x) memset(x, 0, sizeof(x))
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define red(i, a, b) for (int i = (a); i >= (b); --i)
#define PB push_back
#define Inf 0x3fffffff
#define eps 1e-8
#define maxn 50014
typedef long long LL;
using namespace std;
struct TwoSat{
int n;
int S[maxn], c;
bool mark[maxn];
vector<int> G[maxn];
bool dfs(int x){
if (mark[x^]) return false;
if (mark[x]) return true;
mark[x] = true;
S[c++] = x;
for (int i = ; i < (int)G[x].size(); ++i)
if (!dfs(G[x][i])) return false;
return true;
} void init(int n){
this->n = n;
for (int i = ; i < n * ; ++i) G[i].clear();
memset(mark, , sizeof(mark));
} void add_clause(int x, int y){
G[x^].push_back(y);
G[y^].push_back(x);
}
bool solve(){
for (int i = ; i < n * ; i += )
if (!mark[i] && !mark[i+]){
c = ;
if (!dfs(i)){
while (c > ) mark[S[--c]] = false;
if (!dfs(i+)) return false;
}
}
return true;
}
} S;
int n, m; void solve(){
int x, y;
char c1, c2;
S.init(n);
for (int i = ; i < m; ++i){
scanf("%d%c%d%c", &x, &c1, &y, &c2);
x = x * ;
y = y * ;
if (c1 == 'h') ++x;
if (c2 == 'h') ++y;
S.add_clause(x, y);
}
S.G[].push_back();
if (!S.solve()){
puts("bad luck");
return;
}
for (int i = ; i < n; ++i){
if (S.mark[*i]) printf("%dw", i);
else printf("%dh", i);
if (i == n-) puts("");
printf(" ");
}
} int main(){
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
while (scanf("%d%d", &n, &m) == && n){
// init();
solve();
}
fclose(stdin); fclose(stdout);
return ;
}
poj3678:
题意:
有一个有向图G(V,E),每条边e(a,b)上有一个位运算符op(AND, OR或XOR)和一个值c(0或1)。
问能不能在这个图上的每个点分配一个值X(0或1),使得每一条边e(a,b)满足 Xa op Xb = c
思路:
a and b ==1 , !a->a , !b -> b
a and b ==0 , a->!b , b->!a
a or b ==1 , !a->b , !b->a
a or b ==0 , a->!a , b->!b
a xor b ==1 , a->!b,!b->a,!a->b,b->!a
a xor b ==0 , a->b,b->a,!a->!b,!b->!a
至于为什对于a && b == 1 要建立本身到本身反的边,是要推出矛盾。。
code:
/*
* Author: Yzcstc
* Created Time: 2014/3/16 21:06:08
* File Name: poj3678.cpp
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<ctime>
#define M0(x) memset(x, 0, sizeof(x))
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define red(i, a, b) for (int i = (a); i >= (b); --i)
#define PB push_back
#define Inf 0x3fffffff
#define eps 1e-8
#define maxn 4200
typedef long long LL;
using namespace std;
struct TwoSat{
int n;
vector<int> G[maxn];
bool mark[maxn];
int c, S[maxn];
bool dfs(int x){
if (mark[x^]) return false;
if (mark[x]) return true;
mark[x] = true;
S[c++] = x;
for (int i = ; i < G[x].size(); ++i)
if (!dfs(G[x][i])) return false;
return true;
} void init(int n){
this->n = n;
memset(mark, , sizeof(mark));
for (int i = ; i < *n; ++i)
G[i].clear();
} void add_clause(int x, int y){ G[x].push_back(y); } bool solve(){
for (int i = ; i < *n; i += )
if (!mark[i] && !mark[i+]){
c = ;
if (!dfs(i)){
while (c > ) mark[S[--c]] = false;
if (!dfs(i+)) return false;
}
}
return true;
} } S;
int n, m; void solve(){
char s[];
int a, b, c;
S.init(n);
for (int i = ; i < m; ++i){
scanf("%d%d%d%s", &a, &b, &c, &s);
if (s[] == 'A'){
if (c == ) { S.add_clause(a * , a * + ); S.add_clause(b * , b * + ); }
if (c == ) { S.add_clause(b * + , a * ); S.add_clause(a * + , b * ); }
}
if (s[] == 'O'){
if (c == ) { S.add_clause(b * , a * + ); S.add_clause(a * , b * + ); }
if (c == ) { S.add_clause(a * + , a * ); S.add_clause(b * + , b * ); }
}
if (s[] == 'X'){
if (c == ) { S.add_clause(b * , a * + ); S.add_clause(a * , b * + );
S.add_clause(b * + , a * ); S.add_clause(a * + , b * );
}
if (c == ) { S.add_clause(b * , a * ); S.add_clause(a * , b * );
S.add_clause(b * + , a * + ); S.add_clause(a * + , b * + );
}
}
}
if (S.solve()) puts("YES");
else puts("NO");
} int main(){
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
while (scanf("%d%d", &n, &m) == ) solve();
fclose(stdin); fclose(stdout);
return ;
}
Poj3683:
题意:
有一个牧师要给好几对新婚夫妇准备婚礼.,已知每对新婚夫妇的有空的时间以及婚礼持续时间..
问是否可以让每对新婚夫妇都得到该牧师的祝福。如果可以就输出YES以及可行解 不可以就输出NO
思路:
典型的2-sat。只不过多了输出解。
code:
/*
* Author: Yzcstc
* Created Time: 2014/3/18 18:06:09
* File Name: poj3683.cpp
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<ctime>
#define M0(x) memset(x, 0, sizeof(x))
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define red(i, a, b) for (int i = (a); i >= (b); --i)
#define PB push_back
#define Inf 0x3fffffff
#define maxn 8000
#define eps 1e-8
typedef long long LL;
using namespace std;
struct TwoSat{
int n;
vector<int> G[maxn];
int c, S[maxn];
bool mark[maxn];
bool dfs(int x){
if (mark[x^]) return false;
if (mark[x]) return true;
mark[x] = true;
S[c++] = x;
for (int i = ; i < G[x].size(); ++i)
if (!dfs(G[x][i])) return false;
return true;
} void init(int n){
this->n = n;
memset(mark, , sizeof(mark));
for (int i = ; i < *n; ++i)
G[i].clear();
}
void add_clause(int x, int y){
G[x^].push_back(y);
G[y^].push_back(x);
}
bool solve(){
for (int i = ; i < *n; i += )
if (!mark[i] && !mark[i+]){
c = ;
if (!dfs(i)){
while (c > ) mark[S[--c]] = false;
if (!dfs(i+)) return false;
}
}
return true;
}
} S;
int n;
int St[], En[], D[];
bool g[][]; void init(){
int x, y, x2, y2, z;
for (int i = ; i < n; ++i){
scanf("%d:%d %d:%d %d", &x, &y, &x2, &y2, &z);
D[i] = z;
St[i] = x * + y;
En[i] = x2 * + y2;
}
} bool check(int S1, int T1, int S2, int T2){
if (S1 < T2 && S2 < T1) return true;
return false;
} void solve(){
S.init(n);
int S1, T1, S2, T2;
M0(g);
for (int i = ; i < n; ++i)
for (int j = i + ; j < n; ++j){
S1 = St[i], T1 = St[i] + D[i];
S2 = St[j], T2 = St[j] + D[j];
if (check(S1, T1, S2, T2)){ g[i*][j * ] = true; S.add_clause(i * , j * ); }
S1 = St[i], T1 = St[i] + D[i];
S2 = En[j] - D[j], T2 = En[j];
if (check(S1, T1, S2, T2)) { g[i*][j*+] = true; S.add_clause(i * , j * + );}
S1 = En[i] - D[i], T1 = En[i];
S2 = St[j], T2 = St[j] + D[j];
if (check(S1, T1, S2, T2)) { g[i*+][j*] = true; S.add_clause(i * + , j * );}
S1 = En[i] - D[i], T1 = En[i];
S2 = En[j] - D[j], T2 = En[j];
if (check(S1, T1, S2, T2)) { g[i*+][j*+] = true; S.add_clause(i * + , j * + );}
}
if (!S.solve()){puts("NO"); return;}
puts("YES");
vector<int> V;
for (int i = ; i < n; ++i)
if (S.mark[i*]) V.PB(i*);
else V.PB(i*+);
bool flag = true;
for (int i = ; i < V.size(); ++i)
for (int j = i+; j < V.size(); ++j)
if (g[V[i]][V[j]] || g[V[j]][V[i]]) flag = false;
for (int i = ; i < n; ++i){
if (S.mark[i*] == flag){
printf("%02d:%02d %02d:%02d\n", St[i] / , St[i] % , (St[i] + D[i]) / , (St[i] + D[i]) % );
continue;
}
printf("%02d:%02d %02d:%02d\n", (En[i] - D[i]) / , (En[i] - D[i]) % , En[i] / , En[i] % );
}
} int main(){
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
while (scanf("%d", &n) != EOF){
init();
solve();
}
fclose(stdin); fclose(stdout);
return ;
}
Poj3905
题意:
有n个候选人,m组要求,每组要求关系到候选人中的两个人,“+i +j”代表i和j中至少有一人被选中,“-i -j”代表i和j中至少有一人不被选中。“+i -j”代表i被选中和j不被选中这两个事件至少发生一个,“-i +j”代表i不被选中和j被选中这两个事件至少发生一个。问是否存在符合所有m项要求的方案存在。
思路:
简单的2-sat
code:
/*
* Author: Yzcstc
* Created Time: 2014/3/19 0:06:34
* File Name: poj3905.cpp
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<ctime>
#define M0(x) memset(x, 0, sizeof(x))
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define red(i, a, b) for (int i = (a); i >= (b); --i)
#define PB push_back
#define Inf 0x3fffffff
#define eps 1e-8
#define maxn 4000
typedef long long LL;
using namespace std;
struct Twosat{
int n;
int S[maxn], c;
vector<int> G[maxn];
bool mark[maxn];
bool dfs(int x){
if (mark[x^]) return false;
if (mark[x]) return true;
mark[x] = true;
S[c++] = x;
for (int i = ; i < G[x].size(); ++i)
if (!dfs(G[x][i])) return false;
return true;
}
void init(int n){
this->n = n;
memset(mark, , sizeof(mark));
for (int i = ; i < * n; ++i)
G[i].clear();
}
void add_clause(int x, int y){
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]] = false;
if (!dfs(i+)) return false;
}
}
return true;
}
} S;
int n, m; int change(char s[], int n){
int ret = ;
for (int i = ; i < n; ++i)
if(s[i] <= '' && s[i] >= '') ret = ret * + s[i] - ;
return ret;
} void solve(){
int x, y;
char s[], s1[];
S.init(n);
for (int i = ; i < m; ++i){
scanf("%s%s", &s, &s1);
x = change(s, strlen(s)) - ;
y = change(s1, strlen(s1)) - ;
if (s[] == '+' && s1[] == '+') S.add_clause(x * + , y * + );
if (s[] == '+' && s1[] == '-') S.add_clause(x * + , y * );
if (s[] == '-' && s1[] == '+') S.add_clause(x * , y * + );
if (s[] == '-' && s1[] == '-') S.add_clause(x * , y * );
}
if (S.solve()) puts("");
else puts("");
} int main(){
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
while (scanf("%d%d", &n, &m) == ) solve();
fclose(stdin); fclose(stdout);
return ;
}
2-Sat小结的更多相关文章
- python datetime 时间日期处理小结
python datetime 时间日期处理小结 转载请注明出处:http://hi.baidu.com/leejun_2005/blog/item/47f340f1a85b5cb3a50f5232. ...
- python formatters 与字符串 小结 (python 2)
最近学习python 2 ,觉得有必要小结一下关于字符串处理中的formatters, 转载请声明本文的引用出处:仰望大牛的小清新 0.%进行变量取值使用的时机 在python中,如果我们只是需要在字 ...
- 从零开始编写自己的C#框架(26)——小结
一直想写个总结,不过实在太忙了,所以一直拖啊拖啊,拖到现在,不过也好,有了这段时间的沉淀,发现自己又有了小小的进步.哈哈...... 原想框架开发的相关开发步骤.文档.代码.功能.部署等都简单的讲过了 ...
- Python自然语言处理工具小结
Python自然语言处理工具小结 作者:白宁超 2016年11月21日21:45:26 目录 [Python NLP]干货!详述Python NLTK下如何使用stanford NLP工具包(1) [ ...
- java单向加密算法小结(2)--MD5哈希算法
上一篇文章整理了Base64算法的相关知识,严格来说,Base64只能算是一种编码方式而非加密算法,这一篇要说的MD5,其实也不算是加密算法,而是一种哈希算法,即将目标文本转化为固定长度,不可逆的字符 ...
- iOS--->微信支付小结
iOS--->微信支付小结 说起支付,除了支付宝支付之外,微信支付也是我们三方支付中最重要的方式之一,承接上面总结的支付宝,接下来把微信支付也总结了一下 ***那么首先还是由公司去创建并申请使用 ...
- iOS 之UITextFiled/UITextView小结
一:编辑被键盘遮挡的问题 参考自:http://blog.csdn.net/windkisshao/article/details/21398521 1.自定方法 ,用于移动视图 -(void)mov ...
- K近邻法(KNN)原理小结
K近邻法(k-nearst neighbors,KNN)是一种很基本的机器学习方法了,在我们平常的生活中也会不自主的应用.比如,我们判断一个人的人品,只需要观察他来往最密切的几个人的人品好坏就可以得出 ...
- scikit-learn随机森林调参小结
在Bagging与随机森林算法原理小结中,我们对随机森林(Random Forest, 以下简称RF)的原理做了总结.本文就从实践的角度对RF做一个总结.重点讲述scikit-learn中RF的调参注 ...
- Bagging与随机森林算法原理小结
在集成学习原理小结中,我们讲到了集成学习有两个流派,一个是boosting派系,它的特点是各个弱学习器之间有依赖关系.另一种是bagging流派,它的特点是各个弱学习器之间没有依赖关系,可以并行拟合. ...
随机推荐
- 怎么隐藏服务器的IP地址?
服务器一般很少会使用公网地址,直接放置在互联网上使用. 一般是设置成局域网的私网地址,并通过路由器的端口映射,发布在互联网:内部的NAT转换,相当于隐藏了路由器,外网访问并不知道具体服务器的IP地址. ...
- 20172306《Java程序设计》第四周学习总结
20172306 <Java程序设计>第四周学习总结 教材学习内容总结 第四章: 1. 类和对象的回顾:除了看书,我还上网找了一下两者的一些区别. 2. 编写类时,了解到初始化.形式参数. ...
- libnet 库使用(一)
该库的相关资料主要从源码包中获得(假设当前路径为源码包路径): ./sample 中有代码示例 ./doc/html 中html文件可以通过浏览器打开,参看函数定义 想要的基本上sample中都 ...
- qt小程序
hello: #include <QApplication> #include <QLabel> int main(int argc, char *argv[]) { QApp ...
- Spring IOC(八)bean 的创建
Spring IOC(八)bean 的创建 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 参考: 每天用心记录一点点.内 ...
- 爬虫初窥day1:urllib
模拟“豆瓣”网站的用户登录 # coding:utf-8 import urllib url = 'https://www.douban.com/' data = urllib.parse.urlen ...
- ajax之Content-Type决定form-data方式提交还是request-payloud等
1.post请求的Content-Type为application/x-www-form-urlencoded,参数是在请求体中,即上面请求中的Form Data. 在servlet中,可以通过req ...
- 通过 Spring Security配置 解决X-Frame-Options deny 造成的页面空白 iframe调用问题
spring Security下,X-Frame-Options默认为DENY,非Spring Security环境下,X-Frame-Options的默认大多也是DENY,这种情况下,浏览器拒绝当前 ...
- 验证签名机制——java示例
简单的验证公钥私钥签名认证: 公钥是对外公开的部分,私钥是不公开的部分,一般在项目开发中公钥是给用户,私钥是存于服务器上,二者中有一个加密,则需要另外一个来解密. 下面是java实现的一个比较简单的示 ...
- spring学习九 spring aop详解
本文来自于:https://www.cnblogs.com/jingzhishen/p/4980551.html AOP(Aspect-Oriented Programming,面向方面编程),可以说 ...