BOJ 30866 NOT a SAT problem
sorohue가 PS하는 블로그
BOJ 30866 NOT a SAT problem
문제 링크입니다.
문제 요약
주어진 CNF의 결과를 거짓으로 만드세요.
풀이
하나의 OR절만 거짓으로 만들 수 있으면 됩니다. 각 절을 독립적인 문제라고 생각하고 해결해 가며, 한 번이라도 거짓으로 만들 수 있는 절이 확인되면 YES를 출력하고 그대로 프로그램을 종료해 버립시다.
$x_i \vee \lnot x_i$가 어떤 절에 포함되어 있는 경우 그 절은 변수의 값을 어떻게 설정해도 참이 나옵니다. 반대로 각 논리 변수가 최대 하나씩 들어있는 (비어있지 않은) 절이라면, 각 변수의 값을 그 절에서 요구하는 것과 반대로 쥐어주면 그 절을 거짓으로 만들어 전체 CNF를 거짓으로 만들 수 있습니다. 나머지 변수는 아무거나 적당히 주면 됩니다.
길이가 $k$인 절의 거짓화 가능성 판정이 ${\cal O}(k)$에 가능하므로 문제를 ${\cal O}(\Sigma k)$에 해결할 수 있습니다.
코드
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
31
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;
bool ans[505050], vis[505050];
int in[505050];
int main(){
cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
int n, m; cin >> n >> m;
while(m--){
int k; cin >> k;
for(int i = 0; i < k; i++) cin >> in[i];
bool flag = 1;
for(int i = 0; i < k; i++){
if(vis[abs(in[i])] && ((in[i] > 0) != ans[abs(in[i])])){
flag = 0; break;
}
vis[abs(in[i])] = 1;
if(in[i] > 0) ans[in[i]] = 1;
}
if(flag){
cout << "YES\n";
for(int i = 1; i <= n; i++) cout << !ans[i] << ' ';
return 0;
}
for(int i = 0; i < k; i++) ans[abs(in[i])] = vis[abs(in[i])] = 0;
}
cout << "NO";
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.