반응형
❔ 문제
https://www.acmicpc.net/problem/1707
🔍 문제 요약
- 목표: 그래프의 정점 집합을 두 개로 나누었을 때,같은 집합에 속한 정점끼리는 인접하지 않도록 분할이 가능하면 이분 그래프라고 한다. 입력으로 주어진 그래프들이 이분 그래프인지 아닌지 판별하라.
- 입력
- 테스트 케이스 개수 K. 각 테스트 케이스마다
- 정점의 개수 V (1 ≤ V ≤ 20,000)
- 간선의 개수 E (1 ≤ E ≤ 200,000)
- E개의 간선 정보: u v (1 ≤ u, v ≤ V)
- 출력 : 각 그래프가 이분 그래프인지 여부를 YES 또는 NO로 출력
⛔️ 초기시도 (맞긴 함)
#include<iostream>
#include<vector>
#include<queue>
# define MAX 20'001
using namespace std;
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t; cin>>t;
while(t--){
int v,e,isAble=1; cin>>v>>e; //그래프의 정점의 개수 V, 간선의 개수 E
vector<vector<int>> graph(v+1);
// 간선 입력 받기
for(int i=0,a,b;i<e;i++){
cin>>a>>b;
graph[a].push_back(b);
graph[b].push_back(a);
}
//BFS
queue<pair<int,int>> q; // 노드, 추가하려 시도할 그룹
int visit[MAX]={0,};
int V1[MAX]={0,}; // 그룹 1
int V2[MAX]={0,}; // 그룹 2
for(int i=1;i<=v;i++){
if(visit[i]) continue;
q.push({i,1}); visit[i]=1;
while(q.size()){
int node = q.front().first;
int group = q.front().second;
q.pop();
// 1번 그룹에 넣기 시도
if(group ==1){
for(auto adj : graph[node]){
// 해당 그룹에 adj가 이미 들어가 있으면 이분 그래프가 될 수 없음
if(V1[adj]){ isAble=0; break; }
// 아직 방문 안했으면 큐에 추가
if(!visit[adj]){ q.push({adj,2}); visit[adj]=1; }
}
V1[node]=1; // 1번 그룹에 node 추가
}
// 2번 그룹에 넣기 시도
else{
for(auto adj : graph[node]){
if(V2[adj]){ isAble=0; break; }
if(!visit[adj]){ q.push({adj,1}); visit[adj]=1; }
}
V2[node]=1; // 2번 그룹에 node 추가
}
if(!isAble) break;
}
}
//이분 그래프이면 YES, 아니면 NO
if(isAble) cout<<"YES"<<'\n';
else cout<<"NO"<<'\n';
}
}
- 각 그룹을 따로 관리하느라 불필요한 메모리 사용
- 총 정점 수가 최대 2만인데, 그룹 배열이 2개라 메모리 이중 낭비
🔑 해결 전략 : BFS
💙 Step 1: 그룹을 depth 값으로 처리
int v[MAX] = {0}; // depth 기록, 짝수/홀수로 그룹 구분
- depth % 2를 이용해 현재 정점의 그룹을 자동으로 판단
- 1, 2, 3… 으로 레벨을 부여하면
- 짝수 → 그룹 0
- 홀수 → 그룹 1
💙 Step 2 : 같은 그룹인지 확인
if (v[adj] && (v[adj] & 1) == (v[node] & 1)) isAble = 0;
- v[adj] : 이미 방문을 한적이 있는데
- (v[adj] & 1) == (v[node] & 1) : 현재 노드와 인접한 노드가 같은 그룹이라면 isAble = 0;
💙 Step 3 : 모든 정점에 대하여 검사
for(int i=1;i<=vertex;i++){
if(v[i]) continue;
// BFS 수행
- 그래프가 연결되지 않을 수도 있으므로, 모든 정점에서 BFS 시도
- 이미 방문한 정점은 건너뛰기
✅ 최종 코드
// Depth를 이용한 방식(Depth가 홀수면 1번 그룹, 짝수면 0번 그룹)
#include<iostream>
#include<vector>
#include<queue>
# define MAX 20'001
using namespace std;
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t; cin>>t;
while(t--){
int vertex,e,isAble=1; cin>>vertex>>e; //그래프의 정점의 개수 V, 간선의 개수 E
vector<vector<int>> graph(vertex+1);
// 간선 입력 받기
for(int i=0,a,b;i<e;i++){
cin>>a>>b;
graph[a].push_back(b);
graph[b].push_back(a);
}
//BFS
queue<int> q;
int v[MAX]={0,};
for(int i=1;i<=vertex;i++){
if(v[i]) continue;
q.push(i); v[i]=1;
while(q.size()){
int node = q.front(); q.pop();
for(int adj : graph[node]){
// 같은 그룹에 있으면 NO
if(v[adj] && (v[adj]&1) == (v[node]&1)){ isAble=0; break;}
// 아직 방문 안했으면 큐에 추가
if(!v[adj]){ q.push(adj); v[adj]=v[node]+1; }
}
if(!isAble) break;
}
}
if(isAble) cout<<"YES"<<'\n';
else cout<<"NO"<<'\n';
}
}
🏃♀️ 다른 코드
- unionFind로 같은 그룹에 있는지 확인할 수도 있다.
✨ 요약
알고리즘 | BFS |
핵심 아이디어 | depth로 홀짝 구분해서 그룹 나누기 |
포인트 | visit 배열 하나만 사용해서 그룹 체크! |
반응형
'백준' 카테고리의 다른 글
[c++] 15558 점프게임 (0) | 2025.06.08 |
---|---|
[c++] 백준 21940 가운데에서만나기 (0) | 2025.06.08 |
[c++] 6603 로또 - 조합 (0) | 2025.06.06 |
[c++] 2108 통계학 (1) | 2025.06.06 |
[c++] 백준 14888 연산자 끼워넣기 (0) | 2025.05.06 |