https://www.acmicpc.net/problem/3682
목적
명제의 수 n과 증명된 함축 m개가 주어질 때, n개의 명제가 동치가 되기 위해 증명해야할 최소 함축의 개수를 구하자.
접근법
1. x개의 SCC를 1개로 만들기 위해 필요한 간선의 개수를 구하면 된다.
2. 그래프 내의 모든 정점이 사이클을 형성해야 하므로, 정점의 in-degree가 0인 정점의 개수와 out-degree가 0인 정점의 개수 중 최대값이 필요한 간선의 개수이다. 다시 말해 사이클을 형성하기 위해선, in-degree와 out-degree가 0인 정점이 하나도 없어야 한다.
3. 위와 같이 사이클을 형성하기 위한 조건을 알면 아주 쉬운 문제였다...
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
#include<bits/stdc++.h>
#define f(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
typedef vector<int> vi;
const int MAXN=2e4+1;
vi edge[MAXN],redge[MAXN];
int n,idx,order[MAXN],scc[MAXN],in[MAXN],out[MAXN];
bool vis[MAXN];
void sort(int u){
vis[u]=true;
for(int &v:edge[u])if(!vis[v])sort(v);
order[idx--]=u;
}
void findSCC(int u){
vis[u]=true;
for(int &v:redge[u])if(!vis[v])findSCC(v);
scc[u]=idx;
}
void countDegree(int size){
f(i,1,n)for(int &v:edge[i])if(scc[i]!=scc[v]){
++out[scc[i]];
++in[scc[v]];
}
}
int sol(){
idx=n;
f(i,1,n)if(!vis[i])sort(i);
memset(vis, false, n+1);
f(i,1,n)if(!vis[order[i]]){
++idx;
findSCC(order[i]);
}
if(idx==1)return 0;
countDegree(idx+1);
int zeroIn=0, zeroOut=0;
f(i,1,idx){
if(!in[i])++zeroIn;
if(!out[i])++zeroOut;
}
return max(zeroIn,zeroOut);
}
int main(){
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int tc;cin>>tc;
while(tc--){
int m;cin>>n>>m;
f(i,1,n){
edge[i].clear();
redge[i].clear();
in[i]=out[i]=vis[i]=0;
}
while(m--){
int a,b;cin>>a>>b;
edge[a].push_back(b);
redge[b].push_back(a);
}
cout<<sol()<<'\n';
}
return 0;
}
|
문제 설명과 코드에 대한 피드백은 언제나 환영합니다.
다양한 의견 댓글로 남겨주세요.
'Problem Solving > BOJ 백준' 카테고리의 다른 글
[ BOJ 백준 2152번 - 여행 계획 세우기 ] 해설 및 코드 (0) | 2020.03.21 |
---|---|
[ BOJ 백준 3977번 - 축구 전술 ] 해설 및 코드 (0) | 2020.03.20 |
[ BOJ 백준 4196번 - 도미노 ] 해설 및 코드 (1) | 2020.03.17 |
[ BOJ 백준 11097번 - 도시 계획 ] 해설 및 코드 (0) | 2020.03.16 |
[ BOJ 백준 6543번 - 그래프의 싱크 ] 해설 및 코드 (0) | 2020.03.14 |