문제 URL : https://www.acmicpc.net/problem/4196
4196번: 도미노
도미노는 재밌다. 도미노 블록을 일렬로 길게 늘어세운 뒤 블록 하나를 넘어뜨리면 그 블록이 넘어지며 다음 블록을 넘어뜨리는 일이 반복되어 일렬로 늘어선 블록들을 연쇄적으로 모두 쓰러
www.acmicpc.net
문제 접근법 :
ssc + 위상정렬을 이용한 문제입니다.
도미노를 최소한으로 건드려서 다 쓰러뜨리고 싶은데 어떻게 쓰러뜨려야할지 물어보는 문제입니다.
해당 그림이
1->2
2->3
3->2 이럴경우 1번만 건드려서 2,3번을 전부 쓰러트려야하는데 ssc를 어떻게 해결하면 좋을지 생각해야합니다.
ssc로 그룹화 시켜주고 해당 그룹에서 다른그룹으로 가는 indegree가 없다면
그것은 반드시 넘어 뜨려야하는 도미노가 될수밖에없습니다.
소스코드:
#include <bits/stdc++.h>
using namespace std;
int n,m;
vector<vector<int>> adj;
vector<int> check,finish,st;
int id;
int color;
void input(){
cin>>n>>m;
adj = vector<vector<int>>(n+1);
check = finish = vector<int>(n+1);
st.clear();
int a,b;
for(int i=0;i<m;i++){
cin>>a>>b;
adj[a].push_back(b);
}
id = color=0;
}
int scc(int cur){
check[cur]=++id;
st.push_back(cur);
int parent = check[cur];
for(int next : adj[cur]){
if(!check[next])parent = min(parent,scc(next));
else if(!finish[next]) parent= min(parent,check[next]);
}
if (parent==check[cur]){
color++;
while(true){
int node = st.back();
st.pop_back();
finish[node]=color;
if(node==cur)break;
}
}
return parent;
}
void solve(){
for(int i=1;i<=n;i++){
if(!check[i])scc(i);
}
vector<int> indegree(n+1);
int res =0;
for(int i=1;i<=n;i++){
for(int next:adj[i]){
indegree[finish[next]]|=finish[i]!=finish[next];
}
}
for(int i=1;i<=color;i++)res+=!indegree[i];
cout<<res<<"\n";
}
int main ()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
//freopen("input.txt","r",stdin);
int test;
cin>>test;
while(test--){
input();
solve();
}
}
궁금한점 혹은 모르는점 논리적인 오류등
어떤 질문이든 댓글은 언제나 환영입니다.
'백준' 카테고리의 다른 글
백준 9202 Boggle (1) | 2023.12.10 |
---|---|
백준 1506 경찰서 (2) | 2023.12.09 |
백준 16638 괄호 추가하기 2 (1) | 2023.10.15 |
백준 13544 수열과 쿼리 3 (1) | 2023.10.15 |
백준 13905 세부 (0) | 2023.06.15 |