https://www.acmicpc.net/problem/11281
11281번: 2-SAT - 4
첫째 줄에 변수의 개수 N (1 ≤ N ≤ 10,000)과 절의 개수 M (1 ≤ M ≤ 100,000)이 주어진다. 둘째 줄부터 M개의 줄에는 절이 주어진다. 절은 두 정수 i와 j (1 ≤ |i|, |j| ≤ N)로 이루어져 있으며, i와 j가
www.acmicpc.net
11281 2-SAT - 4
알고리즘 : 2-SAT / 강한연결요소(SCC)
이전 글에서 풀었던 2-SAT-3의 심화 문제입니다. 이전 문제는 가능한지 판별만 하였다면,
이번 문제는 가능한 케이스 한 개를 같이 출력하여야 합니다. (스페셜 저지)
isVisited 변수는 SCC를 구성하는 순간 쓸모가 없어지므로 이 변수에 몇 번째 SCC인지를 저장합니다.
그렇게 모든 정점을 SCC 순번이 작은대로 정렬하면 자연스럽게 위상정렬을 한 것처럼 정리가 되어 풀이할 수 있습니다.
< CODE >
#include <iostream>
#include <vector>
#include <cmath>
#include <stack>
#include <set>
#include <algorithm>
using namespace std;
#define MAX 10007
vector<int> adj[2][MAX];
int isVisited[2][MAX];
bool isFinished[2][MAX];
stack<int> s;
int cnt = 0;
int result[MAX];
int SCC;
pair<int,int> p[MAX * 2];
int DFS(int v)
{
int p = ++cnt;
bool isMinus = v < 0;
int basisV = v;
s.push(v);
v = abs(v);
isVisited[isMinus][v] = p;
for(int i = 0; i < adj[isMinus][v].size(); i++)
{
int to = adj[isMinus][v][i];
int isTminus = to < 0;
if(!isVisited[isTminus][abs(to)])
{
p = min(p, DFS(to));
}
else if(!isFinished[isTminus][abs(to)])
{
p = min(p, isVisited[isTminus][abs(to)]);
}
}
if(p == isVisited[isMinus][v])
{
while(!s.empty())
{
int top = s.top(); s.pop();
int isM = top < 0;
isVisited[isM][abs(top)] = SCC + 1;
isFinished[isM][abs(top)] = true;
if(basisV == top)
break;
}
SCC++;
}
return p;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
while(m--)
{
int f, t;
cin >> f >> t;
bool chkF = -f < 0;
bool chkT = -t < 0;
adj[chkT][abs(t)].push_back(f);
adj[chkF][abs(f)].push_back(t);
}
for(int i = 1; i <= n; i++)
{
if(!isVisited[0][i])
DFS(i);
if(!isVisited[1][i])
DFS(-i);
}
for(int j = 1; j <= n; j++)
{
result[j] = -1;
if(isVisited[0][j] == isVisited[1][j])
{
cout << "0\n";
return 0;
}
p[j * 2] = make_pair(isVisited[0][j], j);
p[j * 2 + 1] = make_pair(isVisited[1][j], -j);
}
sort(p + 2, p + n * 2 + 2);
for(int i = n*2+2; i >= 2; i--)
{
int cur = p[i].second;
bool isCminus = cur < 0;
cur = abs(cur);
if(result[cur] == -1)
result[cur] = isCminus;
}
cout << "1\n";
for(int i = 1; i <= n; i++)
cout << result[i] << ' ';
return 0;
}
시간 : 32ms
태그 : #BOJ 2-SAT-4 #BOJ 2-SAT 4 #11281 2-SAT #11281 2-SAT 4 #백준 2-SAT-4 #SCC
'알고리즘' 카테고리의 다른 글
2021 KAKAO BLIND RECRUITMENT 1차예선 풀이 (0) | 2021.08.27 |
---|---|
[BOJ / DFS] 17370 육각형 우리 속의 개미 (0) | 2021.07.30 |
[BOJ / 2-SAT] 11280 2-SAT - 3 (0) | 2021.07.25 |
[BOJ / SCC] 4196 도미노 (0) | 2021.07.20 |
[BOJ / 휴리스틱(시뮬레이티드 어닐링)] 2582 동전 뒤집기 2 (0) | 2021.07.19 |