2-SAT 建图总结

2-SAT:

给定一个由布尔值组成的有 n 个元素的序列 A,再有若干限制,每个限制针对至多两个元素,求满足所有限制的序列 A 或者判定不存在。

常见的限制条件:

记每个限制条件给定 a   o p   b ,   a 0 ,   b 0 ,   a 1 ,   b 1 a~op~b,~a_0,~b_0,~a_1,~b_1 分别代表布尔取值为 0 或 1。
a b a\rightarrow b 代表 a 向 b 连边,表示由 a a 推导出 b b
  a = 1 ,   a 0 a 1 ①~a=1,~a_0\rightarrow a_1
      a = 0 ,   a 1 a 0 ~~~~~a=0,~a_1\rightarrow a_0
  a   &   b = 1 ,   a 0 a 1 ,   b 0 b 1 ②~a~\&~b=1,~a_0\rightarrow a_1,~b_0\rightarrow b_1
      a   &   b = 0 ,   a 1 b 0 ,   b 1 a 0 ~~~~~a~\&~b=0,~a_1\rightarrow b_0,~b_1\rightarrow a_0
  a     b = 1 ,   a 0 b 1 ,   b 0 a 1 ③~a~\mid~b=1,~a_0\rightarrow b_1,~b_0\rightarrow a_1
      a     b = 0 ,   a 1 a 0 ,   b 1 b 0 ~~~~~a~\mid~b=0,~a_1\rightarrow a_0,~b_1\rightarrow b_0
  a   b = 1 ,   a 0 b 1 ,   a 1 b 0 ,   b 0 a 1 ,   b 1 a 0 ④~a~\oplus b=1,~a_0\rightarrow b_1,~a_1\rightarrow b_0,~b_0\rightarrow a_1,~b_1\rightarrow a_0
      a   b = 0 ,   a 0 b 0 ,   a 1 b 1 ,   b 0 a 0 ,   b 1 a 1 ~~~~~a~\oplus b=0,~a_0\rightarrow b_0,~a_1\rightarrow b_1,~b_0\rightarrow a_0,~b_1\rightarrow a_1

两种算法:

  d f s ,   O ( n m ) ①~dfs,~O(nm) ,实际上跑得飞快,可以求出字典序最小的解。
  t a r j a n ,   O ( n + m ) ②~tarjan,~O(n+m) ,强连通分量缩点,无解当且仅当存在 a 0 ,   a 1 a_0,~a_1 在同一个强连通分量里。对于解的输出,缩点后,若 b e l [ a 0 ] b e l [ a 1 ] bel[a_0]\rightarrow bel[a_1] ,则选择 a 1 a_1 ,即缩点后按反拓扑序构造解,而缩点后实则已经是反拓扑序,对于 a 0 ,   a 1 a_0,~a_1 选择缩点后编号较小的一个即可。

相关题目:

https://vjudge.net/problem/HDU-1814 求字典序最小的解
https://vjudge.net/problem/HDU-4421 各种位运算限制建图
https://vjudge.net/problem/Gym-101987K t a r j a n tarjan 缩点输出解

参考代码:

#include<bits/stdc++.h> // HDU-1814

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int maxm = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

vector<int> G[maxn];
int vis[maxn], stk[maxn];
int n, m, top;

int dfs(int u){

	if(vis[u ^ 1]) return 0;
	if(vis[u]) return 1;
	vis[u] = 1, stk[++top] = u;
	for(int i = 0; i < sz(G[u]); ++i){

		int v = G[u][i];
		if(!dfs(v)) return 0;
	}
	return 1;
}

int bisat(){

	for(int i = 0; i < n; ++i) vis[i] = 0;
	for(int i = 0; i < n; ++i){

		if(vis[i] || vis[i ^ 1]) continue;
		top = 0;
		if(!dfs(i)){

			while(top) vis[stk[top--]] = 0;
			if(!dfs(i ^ 1)) return 0;
		}
	}
	return 1;
}

int main() {

	while(scanf("%d%d", &n, &m) != EOF){

		n <<= 1;
		for(int i = 0; i < n; ++i) G[i].clear();
		while(m--){

			int x, y; scanf("%d%d", &x, &y);
			--x, --y;
			G[x].pb(y ^ 1), G[y].pb(x ^ 1);
		}
		for(int i = 0; i < n; ++i) sort(G[i].begin(), G[i].end());
		int ret = bisat();
		if(!ret) printf("NIE\n");
		else{

			for(int i = 0; i < n; ++i) if(vis[i]) printf("%d\n", i + 1);
		}
	}
    return 0;
}
#include<bits/stdc++.h> // HDU-4421

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e3 + 5;
const int maxm = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

vector<int> G[maxn];
int dfn[maxn], low[maxn], stk[maxn], ins[maxn], bel[maxn];
int b[maxn][maxn];
int tot, tim, top, n, m;

void tarjan(int u){

	dfn[u] = low[u] = ++tim, stk[++top] = u, ins[u] = 1;
	for(int i = 0; i < sz(G[u]); ++i){

		int v = G[u][i];
		if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
		else if(ins[v]) low[u] = min(low[u], dfn[v]);
	}
	if(low[u] == dfn[u]){

		int v; ++tot;
		do v = stk[top--], ins[v] = 0, bel[v] = tot; while(v != u);
	}
}

void init(){

	for(int i = 0; i < n; ++i) G[i].clear(), dfn[i] = 0;
	tot = tim = top = 0;
}

int solve(){

	for(int i = 0; i < n; ++i) if(!dfn[i]) tarjan(i);
	for(int i = 0; i < n; ++i) if(bel[i] == bel[i ^ 1]) return 0;
	return 1;
}

int main() {

	while(scanf("%d", &n) != EOF){

		for(int i = 0; i < n; ++i){

			for(int j = 0; j < n; ++j){

				scanf("%d", &b[i][j]);
			}
		}
		int ret = 1; m = n, n <<= 1;
		for(int i = 0; i < 31; ++i){

			init();
			for(int j = 0; j < m; ++j){

				for(int k = 0; k < m; ++k){

					if(j == k) continue;
					int t = (b[j][k] >> i) & 1;
					int x = j << 1, y = k << 1;
					if((j & 1) && (k & 1)){

						if(t) G[x].pb(y ^ 1), G[y].pb(x ^ 1);
						else G[x ^ 1].pb(x), G[y ^ 1].pb(y);
					}
					else if((~j & 1) && (~k & 1)){

						if(t) G[x].pb(x ^ 1), G[y].pb(y ^ 1);
						else G[x ^ 1].pb(y), G[y ^ 1].pb(x);
					}
					else{

						if(t) G[x].pb(y ^ 1), G[x ^ 1].pb(y), G[y].pb(x ^ 1), G[y ^ 1].pb(x);
						else G[x].pb(y), G[x ^ 1].pb(y ^ 1), G[y].pb(x), G[y ^ 1].pb(x ^ 1);
					}
				}
			}
			ret &= solve();
			if(!ret) break;
		}
		printf("%s\n", ret ? "YES" : "NO");
	}
    return 0;
}

 
每人至少猜中两个,即至多猜错一个,设 a ,   b ,   c a,~b,~c 分别为三次是否猜中,则 a b = 1 ,   a c = 1 ,   b c = 1 a\mid b=1,~a\mid c=1,~b\mid c=1
 

#include<bits/stdc++.h> // Gym-101987K

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int maxm = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

vector<int> G[maxn];
int dfn[maxn], low[maxn], stk[maxn], ins[maxn], bel[maxn];
int tot, top, tim, n, m;

void tarjan(int u){

	dfn[u] = low[u] = ++tim, stk[++top] = u, ins[u] = 1;
	for(int i = 0; i < sz(G[u]); ++i){

		int v = G[u][i];
		if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
		else if(ins[v]) low[u] = min(low[u], dfn[v]);
	}
	if(low[u] == dfn[u]){

		int v; ++tot;
		do v = stk[top--], ins[v] = 0, bel[v] = tot;
		while(v != u);
	}
}

void init(){

	for(int i = 0; i < n; ++i) dfn[i] = 0, G[i].clear();
	tot = tim = top = 0;
}

int solve(){

	for(int i = 0; i < n; ++i) if(!dfn[i]) tarjan(i);
	for(int i = 0; i < n; i += 2) if(bel[i] == bel[i ^ 1]) return 0;
	return 1;
}

int main() {

	scanf("%d%d", &n, &m);
	n <<= 1, init();
	while(m--){

		int x, y, z; char sx[2], sy[2], sz[2];
		scanf("%d%s%d%s%d%s", &x, sx, &y, sy, &z, sz);
		--x, --y, --z, x <<= 1, y <<= 1, z <<= 1;
		x |= sx[0] == 'B', y |= sy[0] == 'B', z |= sz[0] == 'B';
		G[x ^ 1].pb(y), G[x ^ 1].pb(z);
		G[y ^ 1].pb(x), G[y ^ 1].pb(z);
		G[z ^ 1].pb(x), G[z ^ 1].pb(y);
	}
	int ret = solve();
	if(!ret) printf("-1\n");
	else{

		for(int i = 0; i < n; i += 2) printf("%c", bel[i] < bel[i ^ 1] ? 'R' : 'B');
		printf("\n");
	}
    return 0;
}
发布了55 篇原创文章 · 获赞 0 · 访问量 1256

猜你喜欢

转载自blog.csdn.net/weixin_44059127/article/details/102747569