백준 20942번 신촌지역 초중고등학생 프로그래밍 대회 동아리 연합 대회
https://www.acmicpc.net/problem/20942
20942번: 신촌지역 초중고등학생 프로그래밍 대회 동아리 연합 대회
첫 번째 자리에는 $15$세의 참가자가 이미 배치되어 있다. 두 번째, 세 번째, 네 번째 자리에 각각 $17$세, $12$세, $19$세의 참가자를 배치하면, $15 \operatorname{\&} 17 = 1$, $15 \operatorname{\&} 12 = 12$, $12
www.acmicpc.net
문제
N개의 자리가 있다.
각각의 자리에는 8세 ~ 19세의 참가자를 배치해야 한다.
M개의 연산에 대해, 두 자리에 대한 비트 연산(bitwise and, bitwise or)을 해서 특정 값을 만족해야 한다.
풀이
https://kdr06006.tistory.com/8
2-SAT
안녕하세요. 오늘은 2-Satisfiability 에 대해 알아보겠습니다. 개념 전체 식이 True가 되도록 변수에 True 또는 False 값을 배정하는 문제입니다. True 또는 False 2지 선다이기 때문에 2-SAT 이라 불립니다. X
kdr06006.tistory.com
이 문제를 2-SAT으로 풀 수 있습니다.
각각의 자리마다 나이 제한이 있습니다. (8세 ~ 19세)
8 ~ 19는 5자리의 비트로 나타낼 수 있습니다.
N개의 자리를 N * 5개의 비트로 나타냅니다.
그리고 각 비트마다 0 또는 1 값을 가질 수 있으니 2개의 정점으로 추가로 분리해줍니다.
총 정점의 수 : N * 10 개
10 * N 개로 정점을 분리한 뒤, 각각에 고유 번호를 부여했습니다.
M개의 데이터에 대해 그래프 모델링을 해야합니다.
아래 4가지 경우의 수를 나눠서 정점을 연결해주면 됩니다.
x & y가 1인 경우
- x와 y 둘 다 1이 되어야 합니다.
- not(x) -> x, not(y) -> y 간선을 추가합니다.
x & y가 0인 경우
- x가 1이면, y는 0이 되어야 합니다.
- y가 1이면, x는 0이 되어야 합니다.
- x -> not(y), y -> not(x) 간선을 추가합니다.
x | y가 1인 경우
- x가 0이면, y는 1이 되어야 합니다.
- y가 0이면, x는 1이 되어야 합니다.
- not(x) -> y, not(y) -> x 간선을 추가합니다.
x | y가 0인 경우
- x와 y 둘 다 0이 되어야 합니다.
- x -> not(x), y -> not(y) 간선을 추가합니다.
N개의 자리에 대한 그래프 모델링도 해야합니다.
a가 0이 아닌 경우
해당 자리에 앉을 나이가 정해진 경우입니다.
각 비트에 대한 0 또는 1의 값이 명확히 할당되기 때문에 이에 맞게 간선을 만들어주면 됩니다.
비트의 값이 1이라면, not(x) -> x
비트의 값이 0이라면, x -> not(x)
a가 0인 경우
해당 자리에 앉을 나이가 정해지지 않은 경우입니다.
8 ~ 19의 값을 가지도록 간선을 만들어줘야 합니다.
N4가 0일 때
N4가 0이면, N3는 무조건 1이여야 합니다.
not(N4) -> N3 간선을 추가해 줍니다.
N4가 1일 때
N4가 1이면, N3와 N2가 0이여야 합니다.
N4 -> not(N3), N4 -> not(N2) 간선을 추가해 줍니다.
N3가 0일 때
N3가 0이면 N4는 1, N2는 0이여야 합니다.
not(N3) -> N4, not(N3) -> not(N2)를 추가해줍니다.
N3가 1일 때
N3가 1이면, N4는 0이여야 합니다.
N3 -> not(N4) 간선을 추가해 줍니다.
N2가 1일 때
N2가 1이면 N4는 0, N3는 1이여야 합니다.
N2 -> not(N4), N2 -> N3 간선을 추가해 줍니다.
총 필요한 간선은 N * 8 + M * 10 개 입니다.
N개의 자리 각각 8 ~ 19 사이의 수를 설정하기 위해 필요한 간선은 최대 8개 입니다.
M개의 연산에 대해 필요한 간선은 최대 10개 입니다.
바로 위의 그래프 모델링 과정을 확인하면 됩니다.
코드
#include <cstdio>
const int VSIZE = 5e4 * 5 * 2 + 4;
const int ESIZE = 5e4 * 8 + 1e5 * 10 + 4;
struct EdgePool {
EdgePool* next;
int x;
}edgePool[ESIZE];
int edgeCnt;
EdgePool* getEdge(int x) {
edgePool[edgeCnt].x = x;
return &edgePool[edgeCnt++];
}
struct Vector {
EdgePool* head;
void push(int x) {
EdgePool* cur = getEdge(x);
cur->next = head;
head = cur;
}
}adj[VSIZE];
struct Stack {
int arr[VSIZE];
int top = -1;
inline bool empty() { return top == -1; }
inline void push(int t) { arr[++top] = t; }
inline int pop() { return arr[top--]; }
};
inline int get(int i, int j, int v) {
return i * 10 + j * 2 + v;
}
inline int min(int a, int b) { return a < b ? a : b; }
struct SCC {
Stack S;
int dfsn[VSIZE], dfsNumber;
int sccn[VSIZE], sccNumber;
bool finish[VSIZE];
int dfs(int cur) {
int ret = dfsn[cur] = ++dfsNumber;
S.push(cur);
for (EdgePool* e = adj[cur].head; e; e = e->next) {
int n = e->x;
if (!dfsn[n]) ret = min(ret, dfs(n));
else if (!finish[n]) ret = min(ret, dfsn[n]);
}
if (ret == dfsn[cur]) {
++sccNumber;
while (!S.empty()) {
int t = S.pop();
sccn[t] = sccNumber;
finish[t] = true;
if (t == cur) break;
}
}
return ret;
}
void solve(int N) {
register int i, j;
for (i = 0; i < N; ++i) {
for (j = 0; j < 5; ++j) {
if (!dfsn[get(i, j, 0)]) dfs(get(i, j, 0));
if (!dfsn[get(i, j, 1)]) dfs(get(i, j, 1));
}
}
if (!TOF(N)) printf("0\n");
else {
printf("1\n");
allocate(N);
}
}
bool TOF(int N) {
register int i, j;
for (i = 0; i < N; ++i) {
for (j = 0; j < 5; ++j) {
if (sccn[get(i, j, 0)] == sccn[get(i, j, 1)])
return false;
}
}
return true;
}
void allocate(int N) {
register int i, j;
for (i = 0; i < N; ++i) {
int ans = 0;
for (j = 4; j >= 0; --j) {
ans <<= 1;
ans += sccn[get(i, j, 0)] > sccn[get(i, j, 1)];
}
printf("%d ", ans);
}
}
}scc;
inline void link(int n1, int n2) {
adj[n1].push(n2);
}
int main()
{
//freopen("input.txt", "r", stdin);
register int i, j;
int N;
scanf("%d", &N);
for (i = 0; i < N; ++i) {
int t;
scanf("%d", &t);
if (t) {
for (j = 0; j < 5; ++j) {
if (t & 1) link(get(i, j, 0), get(i, j, 1));
else link(get(i, j, 1), get(i, j, 0));
t >>= 1;
}
}
else {
link(get(i, 4, 0), get(i, 3, 1));
link(get(i, 4, 1), get(i, 3, 0));
link(get(i, 4, 1), get(i, 2, 0));
link(get(i, 3, 0), get(i, 4, 1));
link(get(i, 3, 0), get(i, 2, 0));
link(get(i, 3, 1), get(i, 4, 0));
link(get(i, 2, 1), get(i, 4, 0));
link(get(i, 2, 1), get(i, 3, 1));
}
}
int M;
char op;
scanf("%d", &M);
while (M--) {
int x, y, z;
scanf(" %c %d %d %d", &op, &x, &y, &z);
--x; --y;
for (j = 0; j < 5; ++j) {
if (op == '&') {
if (z & 1) {
link(get(x, j, 0), get(x, j, 1));
link(get(y, j, 0), get(y, j, 1));
}
else {
link(get(x, j, 1), get(y, j, 0));
link(get(y, j, 1), get(x, j, 0));
}
}
else {
if (z & 1) {
link(get(x, j, 0), get(y, j, 1));
link(get(y, j, 0), get(x, j, 1));
}
else {
link(get(x, j, 1), get(x, j, 0));
link(get(y, j, 1), get(y, j, 0));
}
}
z >>= 1;
}
}
scc.solve(N);
}
'BOJ' 카테고리의 다른 글
[BOJ 18251] 내 생각에 A번인 단순 dfs 문제가 이 대회에서 E번이 되어버린 건에 관하여 (Easy) (0) | 2023.08.24 |
---|---|
[BOJ 3392] 화성 지도 (0) | 2023.08.21 |
[BOJ 13711] LCS 4 (0) | 2023.08.02 |
[BOJ 3648] 아이돌 (0) | 2023.07.26 |
[BOJ 4305] 성격 진단 테스트 (0) | 2023.07.21 |