P3387
题意
思路
- 依据约束关系建图,用\(Tarjan\)跑强连通分量,如果一个值的
true
和false
再同一个强连通分量则无解
- 我觉得最具有争议的地方就是洛谷的输出,输出本来按照缩点后的拓扑序,同一个值的
true
和false
状态选择拓扑序大的作为结果即可,即选SSC
编号小的作为结果
- 但是看贴出的题解都没有说这个问题,我按照前面n个为真,后面n个为假的状态输出,必须设置成选\(SSC\)编号大的,又按照前面n个为假,后面n个为真输出,选择编号的小的,但是和样例答案完全相反,虽然跑出的答案是相反的但也是一种合理方案,没想到竟然能A。。。
代码一(前面为真,后面为假)
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <stack>
using i64 = long long;
using ll = long long;
const int N = 1000005;
int n, m, low[N << 1], num[N << 1], sscid[N << 1], cnt, dfn;
int head[N << 1], ne[N << 2], to[N << 2], idx;
std::stack<int> st;
void init() {
std::memset(low, 0, sizeof(low));
std::memset(num, 0, sizeof(num));
std::memset(sscid, 0, sizeof(sscid));
cnt = 0;
dfn = 0;
std::memset(head, 0, sizeof(head));
std::memset(ne, 0, sizeof(ne));
std::memset(to, 0, sizeof(to));
idx = 0;
return;
}
void addedge(int u, int v) {
++ idx;
to[idx] = v;
ne[idx] = head[u];
head[u] = idx;
return;
}
void dfs(int u) {
st.push(u);
num[u] = low[u] = ++ dfn;
for(int i = head[u]; i; i = ne[i]) {
int v = to[i];
if(!num[v]) {
dfs(v);
low[u] = std::min(low[u], low[v]);
} else if(!sscid[v]) {
low[u] = std::min(low[u], num[v]);
}
}
if(low[u] == num[u]) {
++ cnt;
while(1) {
int v = st.top();
st.pop();
sscid[v] = cnt;
if(v == u) {
break;
}
}
}
return;
}
void tarjan() {
for (int i = 1; i <= (n << 1); ++ i) {
if(!num[i]) {
dfs(i);
}
}
return;
}
bool two_sat() {
tarjan();
for(int i = 1; i <= n; ++ i) {
if(sscid[i] == sscid[i + n]) return false;
}
return true;
}
void slove() {
init();
std::cin >> n >> m;
for (int i = 1; i <= m; ++ i) {
int x, a, y, b;
std::cin >> x >> a >> y >> b;
int nx = x + n, ny = y + n;
if(a == 0 && b == 0) {
addedge(nx, y);
addedge(ny, x);
} else if(a == 0 && b == 1) {
addedge(nx, ny);
addedge(y, x);
} else if(a == 1 && b == 0) {
addedge(x, y);
addedge(ny, nx);
} else if(a == 1 && b == 1) {
addedge(x, ny);
addedge(y, nx);
}
}
if(two_sat()) {
std::cout << "POSSIBLE\n";
for(int i = 1; i <= n; ++ i) {
if(i != 1) std::cout << " ";
std::cout << (sscid[i] < sscid[i + n] ? 0 : 1);
}
std::cout << "\n";
} else {
std::cout << "IMPOSSIBLE\n";
}
return;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
slove();
return 0;
}
代码二(前面为假,后面为真)
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <stack>
using i64 = long long;
using ll = long long;
const int N = 1000005;
int n, m, low[N << 1], num[N << 1], sscid[N << 1], cnt, dfn;
int head[N << 1], ne[N << 2], to[N << 2], idx;
std::stack<int> st;
void init() {
std::memset(low, 0, sizeof(low));
std::memset(num, 0, sizeof(num));
std::memset(sscid, 0, sizeof(sscid));
cnt = 0;
dfn = 0;
std::memset(head, 0, sizeof(head));
std::memset(ne, 0, sizeof(ne));
std::memset(to, 0, sizeof(to));
idx = 0;
return;
}
void addedge(int u, int v) {
++ idx;
to[idx] = v;
ne[idx] = head[u];
head[u] = idx;
return;
}
void dfs(int u) {
st.push(u);
num[u] = low[u] = ++ dfn;
for(int i = head[u]; i; i = ne[i]) {
int v = to[i];
if(!num[v]) {
dfs(v);
low[u] = std::min(low[u], low[v]);
} else if(!sscid[v]) {
low[u] = std::min(low[u], num[v]);
}
}
if(low[u] == num[u]) {
++ cnt;
while(1) {
int v = st.top();
st.pop();
sscid[v] = cnt;
if(v == u) {
break;
}
}
}
return;
}
void tarjan() {
for (int i = 1; i <= (n << 1); ++ i) {
if(!num[i]) {
dfs(i);
}
}
return;
}
bool two_sat() {
tarjan();
for(int i = 1; i <= n; ++ i) {
if(sscid[i] == sscid[i + n]) return false;
}
return true;
}
void slove() {
init();
std::cin >> n >> m;
for (int i = 1; i <= m; ++ i) {
int x, a, y, b;
std::cin >> x >> a >> y >> b;
int nx = x + n, ny = y + n;
if(a == 0 && b == 0) {
// addedge(nx, y);
// addedge(ny, x);
addedge(x, ny);
addedge(y, nx);
} else if(a == 0 && b == 1) {
// addedge(nx, ny);
// addedge(y, x);
addedge(x, y);
addedge(ny, nx);
} else if(a == 1 && b == 0) {
// addedge(x, y);
// addedge(ny, nx);
addedge(nx, ny);
addedge(y, x);
} else if(a == 1 && b == 1) {
// addedge(x, ny);
// addedge(y, nx);
addedge(nx, y);
addedge(ny, x);
}
}
if(two_sat()) {
std::cout << "POSSIBLE\n";
for(int i = 1; i <= n; ++ i) {
if(i != 1) std::cout << " ";
std::cout << (sscid[i] < sscid[i + n] ? 1 : 0);
}
std::cout << "\n";
} else {
std::cout << "IMPOSSIBLE\n";
}
return;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
slove();
return 0;
}