-
(라이님 블로그 대회 알고리즘 따라잡기 24) 2-SAT(Satisfiability Problem)PROGRAMMING/알고리즘 2024. 7. 12. 11:36
라이님 블로그에서 이번에는 2-SAT(2-Satisfiability Problem)을 배워보았다.
아직도 끝나지 않은 그래프 지옥...★
코드는 저번 SCC 코드랑 비슷한 방식으로 작성해보았다.
#include <iostream> #include <vector> #include <stack> #include <algorithm> #include <cstring> using namespace std; constexpr int MAX = 10000; int N, M, id = 0, disc[MAX * 2], sccCount = 0; bool fin[MAX * 2]; vector<int> adj[MAX * 2]; vector<int> sccID(MAX * 2); stack<int> st; inline int oppo(int n) { return n % 2 ? n - 1 : n + 1; }; int dfs(int u) { disc[u] = ++id; st.push(u); int parent = disc[u]; for (int v : adj[u]) { if (disc[v] == 0) parent = min(parent, dfs(v)); else if (!fin[v]) parent = min(parent, disc[v]); } if (parent == disc[u]) { while (true) { int t = st.top(); st.pop(); fin[t] = true; sccID[t] = sccCount; if (t == u) break; } sccCount++; } return parent; } int main() { memset(disc, 0, sizeof(disc)); memset(fin, 0, sizeof(fin)); cin >> N >> M; for (int i = 0; i < M; i++) { int A, B; cin >> A >> B; A = (A < 0 ? -(A + 1) * 2 : A * 2 - 1); B = (B < 0 ? -(B + 1) * 2 : B * 2 - 1); adj[oppo(A)].push_back(B); // not A -> B adj[oppo(B)].push_back(A); // not B -> A } for (int i = 0; i < N * 2; i++) { if (disc[i] == 0) dfs(i); } for (int i = 0; i < N; i++) { if (sccID[i * 2] == sccID[i * 2 + 1]) { cout << "0" << endl; return 0; } } cout << "1" << endl; return 0; }
✨ DFS를 사용하여 위상 정렬을 수행할 수 있는데, 그래프를 DFS로 탐색한 후 각 정점의 종료 시간을 기준으로 역순으로 나열하면 위상 정렬 순서가 된다.
#include <iostream> #include <vector> #include <stack> #include <algorithm> #include <cstring> using namespace std; constexpr int MAX = 10000; int N, M, id = 0, disc[MAX * 2], sccCount = 0; bool fin[MAX * 2]; vector<int> adj[MAX * 2]; vector<int> sccID(MAX * 2); stack<int> st; inline int oppo(int n) { return n % 2 ? n - 1 : n + 1; }; int dfs(int u) { disc[u] = ++id; st.push(u); int parent = disc[u]; for (int v : adj[u]) { if (disc[v] == 0) parent = min(parent, dfs(v)); else if (!fin[v]) parent = min(parent, disc[v]); } if (parent == disc[u]) { while (true) { int t = st.top(); st.pop(); fin[t] = true; sccID[t] = sccCount; if (t == u) break; } sccCount++; } return parent; } int main() { memset(disc, 0, sizeof(disc)); memset(fin, 0, sizeof(fin)); cin >> N >> M; for (int i = 0; i < M; i++) { int A, B; cin >> A >> B; A = (A < 0 ? -(A + 1) * 2 : A * 2 - 1); B = (B < 0 ? -(B + 1) * 2 : B * 2 - 1); adj[oppo(A)].push_back(B); // not A -> B adj[oppo(B)].push_back(A); // not B -> A } for (int i = 0; i < N * 2; i++) { if (disc[i] == 0) dfs(i); } for (int i = 0; i < N; i++) { if (sccID[i * 2] == sccID[i * 2 + 1]) { cout << "0" << endl; return 0; } } // 각 변수의 참, 거짓값 알아보기 int result[MAX]; memset(result, -1, sizeof(result)); pair<int, int> p[MAX * 2]; for (int i = 0; i < N * 2; i++) p[i] = make_pair(sccID[i], i); sort(p, p + N * 2); // SCC 번호가 크면 클수록 DAG 상에서 앞에 있음 for (int i = N * 2 - 1; i >= 0; i--) { int var = p[i].second; if (result[var / 2] == -1) result[var / 2] = !(var % 2); } for (int i = 0; i < N; i++) { cout << result[i] << " "; } cout << endl; cout << "1" << endl; return 0; }
'PROGRAMMING > 알고리즘' 카테고리의 다른 글
(라이님 블로그 대회 알고리즘 따라잡기 26) 이분매칭(Bipartite Matching) (0) 2024.07.22 (라이님 블로그 대회 알고리즘 따라잡기 25) 네트워크 유량(Network Flow) (0) 2024.07.16 Articulation point(단절점) 구하는 알고리즘 (1) 2024.07.08 (백준 4196번 도미노) (라이님 블로그 대회 알고리즘 따라잡기 22) SCC (0) 2024.07.04 (라이님 블로그 대회 알고리즘 따라잡기 22) 강한 연결 요소(Strongly Connected Component) (0) 2024.07.02