2−SAT 2 − S A T 是一个不是很难的建模的问题(比起网络流)
是由很多个最多只有两个布尔变量限制的东西
求解一般是要找到题目满足限制的可行解
这里大概写下算法流程,就不写证明了
首先对题目限制进行连边建图,边的意思表示起点的信息能推出终点的信息
建好图后如果一个变量为真和一个变量为假在一个强连通分量里,那么肯定是无解的
所以我们用 Tarjan T a r j a n 缩点
求解方案的时候建反图拓扑排序就好了 即选择原图拓扑序大的
但是 Tarjan T a r j a n 有个很棒的性质 就是它的强连通分量编号大小与拓扑序是相反的
利用这个性质我们就不用拓扑排序了 直接比较强连通分量编号大小,优先选择小的
洛谷模板
这里面是把取
x
x
这个变量记为了
所以输出的时候是
be[i+n]<be[i]
b
e
[
i
+
n
]
<
b
e
[
i
]
直接建图缩点就好了
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
int head[N], nxt[N], to[N], e;
int n, m, color, be[N];
void add(int x, int y) {
to[++ e] = y; nxt[e] = head[x]; head[x] = e;
}
namespace Tarjan {
int low[N], dfn[N], cnt, Sta[N], top, ins[N];
void dfs(int x) {
dfn[x] = low[x] = ++ cnt; Sta[++ top] = x; ins[x] = 1;
for(int i = head[x], v = to[i]; i; i = nxt[i], v = to[i]) {
if(!dfn[v]) {
dfs(v);
low[x] = min(low[x], low[v]);
}
else if(ins[v])
low[x] = min(low[x], dfn[v]);
}
if(low[x] == dfn[x]) {
++ color;
do {
ins[Sta[top]] = 0;
be[Sta[top]] = color;
}while(Sta[top --] != x);
}
}
}
bool Topsort() {
queue<int> q;
for(int i = 1; i <= n; ++ i)
if(be[i] == be[i + n])
return false;
puts("POSSIBLE");
for(int i = 1; i <= n; ++ i)
printf("%d ", be[i + n] < be[i]);
return true;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("4782.in", "r", stdin);
freopen("4782.out", "w", stdout);
#endif
int a1, x, a2, y;
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; ++ i) {
scanf("%d%d%d%d", &a1, &x, &a2, &y);
add(a1 + (x ^ 1) * n, a2 + y * n);
add(a2 + (y ^ 1) * n, a1 + x * n);
}
for(int i = 1; i <= (n << 1); ++ i)
if(!Tarjan::dfn[i])
Tarjan::dfs(i);
if(!Topsort())
puts("IMPOSSIBLE");
return 0;
}
2-SAT模板链接
这个差不多算
2−sat
2
−
s
a
t
模板吧…但我还是调了蛮久的
就发现
x
x
类型的地图不好处理
但是发现地图数量很少
考虑枚举每一种
x
x
的情况
对于每种情况跑一次的判定是否有解就可以了
当然 一个比较恶心的地方就是连边的时候连出了不存在的点
如果不存在的点是起点还好,怎么都不会被选到
但是如果不存在的点是终点,我们显然就不能让起点被选
那我们就直接向这个点所对应的另一个限制点连边
以上感谢 ylsoi julao y l s o i j u l a o 的讲解
还有一个东西就是拓扑序的性质,打完之后发现怎么和之前打的板子不一样
这个题如果
i
i
拓扑序在前面,意味着选了
i
i
就要选
所以我们肯定选
i′
i
′
,即拓扑序大的点.
复杂度 O(2d(n+m)) O ( 2 d ( n + m ) )
Codes
#include<bits/stdc++.h>
#define pb push_back
#define mem(a, b) memset(a, b, sizeof(a))
using namespace std;
const int N = 1e5 + 10;
vector<int> G[N];
int X[10], n, d, m;
int be[N], color;
string s;
struct edge {
char hx, hy;
int x, y;
}E[N];
int num(int _, char __) {
if(s[_ - 1] == 'a') return __ == 'C';
if(s[_ - 1] == 'b') return __ == 'C';
if(s[_ - 1] == 'c') return __ == 'B';
}
char cha(int _, int __) {
//cout << s[_ - 1] << endl;
if(s[_ - 1] == 'a') return 'C' - __;
if(s[_ - 1] == 'b') return 'C' - (__ << 1);
if(s[_ - 1] == 'c') return 'B' - __;
}
namespace Tarjan {
int dfn[N], low[N], Sta[N], top, cnt, ins[N];
void Graph_Clear() {
vector<int> Ga[N]; swap(Ga, G);
cnt = top = color = 0;
mem(dfn, 0), mem(be, 0);
}
void dfs(int x) {
low[x] = dfn[x] = ++ cnt; Sta[++ top] = x; ins[x] = 1;
for(auto v : G[x]) {
if(!dfn[v]) {
dfs(v);
low[x] = min(low[x], low[v]);
}
else if(ins[v])
low[x] = min(low[x], dfn[v]);
}
if(low[x] == dfn[x]) {
++ color;
do {
ins[Sta[top]] = 0;
be[Sta[top]] = color;
}while(Sta[top --] != x);
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("2305.in", "r", stdin);
freopen("2305.out", "w", stdout);
#endif
cin >> n >> d >> s;
for(int i = 0; i < n; ++ i)
if(s[i] == 'x')
X[++ X[0]] = i;
scanf("%d", &m);
for(int i = 1; i <= m; ++ i) {
scanf("%d", &E[i].x); cin >> E[i].hx;
scanf("%d", &E[i].y); cin >> E[i].hy;
}
for(int j = 0; j < (1 << d); ++ j) {
int flag = 0;
Tarjan::Graph_Clear();
for(int i = 1; i <= X[0]; ++ i) s[X[i]] = (1 << (i - 1)) & j ? 'a' : 'b';
for(int i = 1; i <= m; ++ i) {
if(E[i].hx + 32 == s[E[i].x - 1]) continue;
int fx = num(E[i].x, E[i].hx), fy = num(E[i].y, E[i].hy);
if(E[i].hy + 32 == s[E[i].y - 1]) {
// cout << i << ' ' << E[i].x + fx * n << ' ' << E[i].x + (fx ^ 1) * n << endl;
G[E[i].x + fx * n].pb(E[i].x + (fx ^ 1) * n); continue;
}
//cout << fx << ' ' << E[i].hx << ' ' << fy << ' ' << E[i].hy << endl;
G[E[i].x + fx * n].pb(E[i].y + fy * n), G[E[i].y + (fy ^ 1) * n].pb(E[i].x + (fx ^ 1) * n);
// cout << i << ' ' << E[i].x + fx * n << ' ' << E[i].y + fy * n << endl;
// cout << i << ' ' << E[i].y + (fy ^ 1) * n << ' ' << E[i].x + (fx ^ 1) * n << endl;
}
//puts("");
for(int i = 1; i <= (n << 1); ++ i) if(!Tarjan::dfn[i]) Tarjan::dfs(i);
for(int i = 1; i <= n; ++ i) if(be[i] == be[i + n]) {flag = 1; break;}
if(flag) continue;
for(int i = 1; i <= n; ++ i)
printf("%c", cha(i, be[i] < be[i + n]));
return 0;
}
puts("-1");
return 0;
}