티스토리 뷰

Algorithm

[백준 3648] 아이돌

devbelly 2020. 8. 12. 11:08

문제

https://www.acmicpc.net/problem/3648

 

알고리즘

2-SAT

 

풀이

문제에서 2-SAT의 느낌을 물씬 풍기는 문장이 몇 있습니다. '적어도 하나'라는 문장은 OR을 연상케 하고 OR은 2-CNF에서 하나의 절을 구성합니다. 그리고 한 참가자에 대해 두 가지 선택을 할 수 있다는 점도 True와 False로 연관 지을 수 있으니 2-SAT으로 문제를 접근합시다.

 

심사위원의 의심 없이 다음라운드를 구성할 수 있다면 하나의 참가자에 대해 모순이 되는 경우가 없다는 의미와 같습니다. 즉, 각 정점의 True와 False의 $sccid$가 일치해서는 안됩니다.

상근이가 진출하는 경우는 그래프상에서 상근이의 False 정점이 True 정점보다 위상정렬상 빠른지 확인하면 됩니다.

이전 문제에서 위상정렬상 빠른 정점을 False로 평가하는 것이 True로 평가하는 것보다 항상 이득임을 확인했습니다.

 

코드

#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;++i)
#define REP(i,n) for(int i=1;i<=n;++i)
#define FAST cin.tie(NULL);cout.tie(NULL); ios::sync_with_stdio(false)
using namespace std;

#define T(x) (x<<1)
#define F(x) (x<<1|1)

int n, m, a, b, VC, SC;

vector<vector<int>> adj;
vector<int> discovered, sccid;
stack<int> st;
int scc(int here) {
    int ret = discovered[here] = VC++;
    st.emplace(here);

    for (auto there : adj[here]) {
        if (discovered[there] == -1) ret = min(ret, scc(there));
        else if (sccid[there] == -1) ret = min(ret, discovered[there]);
    }

    if (ret == discovered[here]) {
        while (1) {
            int t = st.top();
            st.pop();
            sccid[t] = SC;
            if (t == here) break;
        }
        SC++;
    }
    return ret;
}

void OR(int A, int B) {
    adj[A ^ 1].emplace_back(B);
    adj[B ^ 1].emplace_back(A);
}

int main() {
    FAST;
    while (cin >> n >> m) {
        VC = SC = 0;
        adj.clear();
        adj.resize(n << 1);
        discovered.clear();
        sccid.clear();
        discovered = sccid = vector<int>(n << 1, -1);

        while (m--) {
            cin >> a >> b;
            a = a > 0 ? T(a - 1) : F(~a);
            b = b > 0 ? T(b - 1) : F(~b);
            OR(a, b);
        }

        rep(i, n << 1) if (discovered[i] == -1) scc(i);

        bool flag = true;
        for (int i = 0;i < n;++i) if (sccid[i] == sccid[i ^ 1]) {
            flag = false;
            break;
        }

        if (sccid[0] > sccid[1]) flag = false;

        cout << (flag ? "yes" : "no") << '\n';

    }

    return 0;
}

'Algorithm' 카테고리의 다른 글

[백준 16915] 호텔 관리  (0) 2020.08.14
[백준 15675] 괴도 강산  (0) 2020.08.13
[백준 11281] 2-SAT - 4  (0) 2020.08.10
[백준 11280] 2-SAT -3  (0) 2020.08.09
[백준 15483] 최소 편집  (0) 2020.08.06
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함