반응형
12-11 17:51
Today
Total
«   2024/12   »
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
관리 메뉴

개발하는 고라니

[백준] 1707번 : 이분 그래프 본문

Programming/백준

[백준] 1707번 : 이분 그래프

조용한고라니 2021. 1. 22. 21:45
반응형
 

1707번: 이분 그래프

입력은 여러 개의 테스트 케이스로 구성되어 있는데, 첫째 줄에 테스트 케이스의 개수 K(2≤K≤5)가 주어진다. 각 테스트 케이스의 첫째 줄에는 그래프의 정점의 개수 V(1≤V≤20,000)와 간선의 개수

www.acmicpc.net

# 문제

그래프의 정점의 집합을 둘로 분할하여, 각 집합에 속한 정점끼리는 서로 인접하지 않도록 분할할 수 있을 때, 그러한 그래프를 특별히 이분 그래프 (Bipartite Graph) 라 부른다.

그래프가 입력으로 주어졌을 때, 이 그래프가 이분 그래프인지 아닌지 판별하는 프로그램을 작성하시오.

# 입력

입력은 여러 개의 테스트 케이스로 구성되어 있는데, 첫째 줄에 테스트 케이스의 개수 K(2≤K≤5)가 주어진다. 각 테스트 케이스의 첫째 줄에는 그래프의 정점의 개수 V(1≤V≤20,000)와 간선의 개수 E(1≤E≤200,000)가 빈 칸을 사이에 두고 순서대로 주어진다. 각 정점에는 1부터 V까지 차례로 번호가 붙어 있다. 이어서 둘째 줄부터 E개의 줄에 걸쳐 간선에 대한 정보가 주어지는데, 각 줄에 인접한 두 정점의 번호가 빈 칸을 사이에 두고 주어진다.

# 출력

K개의 줄에 걸쳐 입력으로 주어진 그래프가 이분 그래프이면 YES, 아니면 NO를 순서대로 출력한다.

# 예제 입력 1

2

3 2

1 3

2 3

4 4

1 2

2 3

3 4

4 2

# 예제 출력 1

YES

NO

# 알고리즘 분류

  • 그래프 탐색
  • 그래프 이론
  • BFS
  • DFS

BFS 혹은 DFS를 이용해도 되는 것 같다. 필자는 DFS를 이용해서 해결하였다. 우선 이분 그래프가 무엇인지 모른 상태에서 해결하려고 하여 조금 막막하였으나 생각보다 그리 어렵지 않은 이론이었다. 이분 그래프란 간단히 말하자면

 

각 정점을 Red와 Blue의 집합으로 나눈다. 모든 간선들은 반드시 Red와 Blue 정점을 이어야 한다. 간선 기준 양쪽에 동일한 색을 가진 정점이 있으면 그것은 이분 그래프가 아니다.

 

위 그림처럼 Red정점은 다른 Red정점과 인접하지 않아야하고, Blue정점은 다른 Blue 정점과 인접하지 않아야한다.

 

우선 정점을 Class로서 만들었다.

static Class Vertex
{
    int index; // n번 째 정점
    int state = 0; //초기값 : 0, 추후 1 또는 -1을 부여받게 됨
    List<Integer> list = new ArrayList<>(); //인접리스트
    
    public Vertex(int index){
    	this.index = index;
    }
}    

각 정점은 어디로 연결되는지, 자신이 몇 번째 정점인지, 자신의 색깔이 Red(1)인지 Blue(-1)인지 정보를 갖는다.

다음은 DFS 함수와 정답을 결정 짓는 전역변수 bipartite이다.

static boolean bipartite; //이분 그래프의 조건에 적합하지 않으면 false

static void DFS(int start){

  //start번 째 정점 방문
  visit[start] = true;
  //System.out.println(start+" 방문 & state: " + vertices[start].state);

  //start번째 정점의 인접리스트 순회
  vertices[start].list.stream().forEach(i->{
    
    //방문하지 않음 & 색깔을 갖지 않았다면
    if(!visit[i] && vertices[i].state == 0){
      vertices[i].state = vertices[start].state * (-1); //start번 째 정점과 다른 색
      DFS(i);
    }
    //인접리스트에 연결된 다른 정점이 나와 같은 색깔이라면
    //이분 그래프가 아님
    else if(vertices[i].state == vertices[start].state)
      bipartite = false;
  });
}

 

bipartitie의 값에 따라 답이 "YES" or "NO"로 결정된다. 모든 정점을 방문할 때 까지 bipartite가 true를 유지하면 이분 그래프라는 뜻이다.

 

추가)

1 ㅡ 2

3     4

 

같은 그래프도 이분 그래프이다.

 

# Whole Code </>

public class Main {

    static class Vertex{
        int index; //1~v
        int state = 0;//-1, 0, 1
        List<Integer> list = new ArrayList<>();

        public Vertex(int index){
            this.index=index;
        }
    }
    static Vertex[] vertices;
    static boolean[] visit;
    static boolean bipartite; //이분 그래프의 조건에 적합하지 않으면 false

    static void DFS(int start){

        visit[start] = true;
        //System.out.println(start+" 방문 & state: " + vertices[start].state);

        vertices[start].list.stream().forEach(i->{
        
            if(!visit[i] && vertices[i].state == 0){
                vertices[i].state = vertices[start].state * (-1);
                DFS(i);
            }
            
            else if(vertices[i].state == vertices[start].state)
                bipartite = false;
        });
    }

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = null;

        int k = Integer.parseInt(br.readLine()); //test case 개수

        for(int i=0; i<k; i++){
            bipartite = true;
            st = new StringTokenizer(br.readLine());
            int v = Integer.parseInt(st.nextToken()); //정점 개수
            int e = Integer.parseInt(st.nextToken()); //간선 개수

            visit = new boolean[v+1]; //1~v
            vertices = new Vertex[v+1];

            for(int j=1; j<=v; j++)
                vertices[j] = new Vertex(j);

            for(int j=1; j<=e; j++){
                st = new StringTokenizer(br.readLine());
                int left = Integer.parseInt(st.nextToken());
                int right = Integer.parseInt(st.nextToken());

                vertices[left].list.add(right);
                vertices[right].list.add(left);
            }
            vertices[1].state = 1;
            DFS(1);

            for(int j=1; j<=v; j++)
                if(!visit[j]) {
                    vertices[j].state = 1;
                    DFS(j);
                }

            if(bipartite) System.out.println("YES");
            else System.out.println("NO");
        }
    }
}
반응형

'Programming > 백준' 카테고리의 다른 글

[백준] 14501번 : 퇴사  (0) 2021.01.25
[백준] 1520번 : 내리막 길  (0) 2021.01.24
[백준] 7562번 : 나이트의 이동  (0) 2021.01.22
[백준] 2206번 : 벽 부수고 이동하기  (0) 2021.01.22
[백준] 1697번 : 숨바꼭질  (0) 2021.01.22
Comments