www.acmicpc.net/problem/2668

 

2668번: 숫자고르기

세로 두 줄, 가로로 N개의 칸으로 이루어진 표가 있다. 첫째 줄의 각 칸에는 정수 1, 2, …, N이 차례대로 들어 있고 둘째 줄의 각 칸에는 1이상 N이하인 정수가 들어 있다. 첫째 줄에서 숫자를 적절

www.acmicpc.net

문제

세로 두 줄, 가로로 N개의 칸으로 이루어진 표가 있다. 첫째 줄의 각 칸에는 정수 1, 2, …, N이 차례대로 들어 있고 둘째 줄의 각 칸에는 1이상 N이하인 정수가 들어 있다. 첫째 줄에서 숫자를 적절히 뽑으면, 그 뽑힌 정수들이 이루는 집합과, 뽑힌 정수들의 바로 밑의 둘째 줄에 들어있는 정수들이 이루는 집합이 일치한다. 이러한 조건을 만족시키도록 정수들을 뽑되, 최대로 많이 뽑는 방법을 찾는 프로그램을 작성하시오. 예를 들어, N=7인 경우 아래와 같이 표가 주어졌다고 하자.

이 경우에는 첫째 줄에서 1, 3, 5를 뽑는 것이 답이다. 첫째 줄의 1, 3, 5밑에는 각각 3, 1, 5가 있으며 두 집합은 일치한다. 이때 집합의 크기는 3이다. 만약 첫째 줄에서 1과 3을 뽑으면, 이들 바로 밑에는 정수 3과 1이 있으므로 두 집합이 일치한다. 그러나, 이 경우에 뽑힌 정수의 개수는 최대가 아니므로 답이 될 수 없다.

입력

첫째 줄에는 N(1≤N≤100)을 나타내는 정수 하나가 주어진다. 그 다음 줄부터는 표의 둘째 줄에 들어가는 정수들이 순서대로 한 줄에 하나씩 입력된다.

출력

첫째 줄에 뽑힌 정수들의 개수를 출력하고, 그 다음 줄부터는 뽑힌 정수들을 작은 수부터 큰 수의 순서로 한 줄에 하나씩 출력한다.

예제 입력 1

7

3

1

1

5

5

4

6

예제 출력 1

3

1

3

5

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;

public class Main {
    static int[] map = null;
    static int[] check = null;
    static ArrayList<Integer> cycleNodeList = null;
    static boolean isCycle;
    static int cycleStartNode;

    public static void dfs(int node) {
        int next = map[node];
        if(check[next] == 0) {
            check[next] = check[node];
            dfs(next);
        }else if(check[next] == check[node]) {
            isCycle = true;
            cycleStartNode = next;
        }

        if(isCycle) {
            cycleNodeList.add(node);
        }
        if(node == cycleStartNode) {
            isCycle = false;
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        map = new int[n + 1];
        check = new int[n + 1];
        cycleNodeList = new ArrayList<>();
        for(int i = 1; i <= n; i++) {
            map[i] = Integer.parseInt(br.readLine());
        }

        int dfsCnt = 1;
        for(int i = 1; i <= n; i++) {
            if(check[i] == 0) {
                check[i] = dfsCnt;
                dfs(i);
                dfsCnt += 1;
            }
        }

        Collections.sort(cycleNodeList);
        System.out.println(cycleNodeList.size());
        for(int node : cycleNodeList) {
            System.out.println(node);
        }
    }
}

 

N제한을 제외하고는 codeung.tistory.com/177 와 완전히 동일한 문제.

 

여기서는 N제한이 작기 때문에 위 문제에서 시간초과 맞은 코드로도 통과할 수 있다.

(돌려보니까 통과는 하는데.. 이게 더 빠르게 돌아가네..?)

 

www.acmicpc.net/problem/2667

 

2667번: 단지번호붙이기

<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여

www.acmicpc.net

문제

<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여기서 연결되었다는 것은 어떤 집이 좌우, 혹은 아래위로 다른 집이 있는 경우를 말한다. 대각선상에 집이 있는 경우는 연결된 것이 아니다. <그림 2>는 <그림 1>을 단지별로 번호를 붙인 것이다. 지도를 입력하여 단지수를 출력하고, 각 단지에 속하는 집의 수를 오름차순으로 정렬하여 출력하는 프로그램을 작성하시오.

입력

첫 번째 줄에는 지도의 크기 N(정사각형이므로 가로와 세로의 크기는 같으며 5≤N≤25)이 입력되고, 그 다음 N줄에는 각각 N개의 자료(0혹은 1)가 입력된다.

출력

첫 번째 줄에는 총 단지수를 출력하시오. 그리고 각 단지내 집의 수를 오름차순으로 정렬하여 한 줄에 하나씩 출력하시오.

예제 입력 1

7

0110100

0110101

1110101

0000111

0100000

0111110

0111000

예제 출력 1

3

7

8

9

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;

public class Main {
    static int[][] map = null;
    static boolean[][] check = null;
    static ArrayList<Integer> sizeList = null;

    static int[] rArr = {-1, 1, 0, 0};
    static int[] cArr = {0, 0, -1, 1};

    static int n = 0;
    static int componentCnt = 0;
    static int componentSize = 0;

    public static void dfs(int r, int c) {
        for(int i = 0; i < 4; i++) {
            int nr = r + rArr[i];
            int nc = c + cArr[i];
            if(0 <= nr && nr < n && 0 <= nc && nc < n &&
                    map[nr][nc] == 1 && !check[nr][nc]) {
                check[nr][nc] = true;
                dfs(nr, nc);
            }
        }
        componentSize += 1;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(br.readLine());

        map = new int[n][n];
        check = new boolean[n][n];
        sizeList = new ArrayList<>();
        for(int i = 0; i < n; i++) {
            char[] ch = br.readLine().toCharArray();
            for(int j = 0; j < n; j++) {
                map[i][j] = ch[j] - '0';
            }
        }

        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                if(map[i][j] == 1 && !check[i][j]) {
                    check[i][j] = true;
                    dfs(i, j);
                    sizeList.add(componentSize);  // 각 구성요소마다 사이즈를 기억
                    componentCnt += 1;
                    componentSize = 0;
                }
            }
        }

        Collections.sort(sizeList);
        System.out.println(componentCnt);
        for(int size : sizeList) {
            System.out.println(size);
        }
    }
}

 

DFS 돌리면서 componentSize를 함께 센다.

www.acmicpc.net/problem/9466

 

9466번: 텀 프로젝트

이번 가을학기에 '문제 해결' 강의를 신청한 학생들은 텀 프로젝트를 수행해야 한다. 프로젝트 팀원 수에는 제한이 없다. 심지어 모든 학생들이 동일한 팀의 팀원인 경우와 같이 한 팀만 있을

www.acmicpc.net

문제

이번 가을학기에 '문제 해결' 강의를 신청한 학생들은 텀 프로젝트를 수행해야 한다. 프로젝트 팀원 수에는 제한이 없다. 심지어 모든 학생들이 동일한 팀의 팀원인 경우와 같이 한 팀만 있을 수도 있다. 프로젝트 팀을 구성하기 위해, 모든 학생들은 프로젝트를 함께하고 싶은 학생을 선택해야 한다. (단, 단 한 명만 선택할 수 있다.) 혼자 하고 싶어하는 학생은 자기 자신을 선택하는 것도 가능하다.

학생들이(s1, s2, ..., sr)이라 할 때, r=1이고 s1이 s1을 선택하는 경우나, s1이 s2를 선택하고, s2가 s3를 선택하고,..., sr-1이 sr을 선택하고, sr이 s1을 선택하는 경우에만 한 팀이 될 수 있다.

예를 들어, 한 반에 7명의 학생이 있다고 하자. 학생들을 1번부터 7번으로 표현할 때, 선택의 결과는 다음과 같다.

1234567

3 1 3 7 3 4 6

위의 결과를 통해 (3)과 (4, 7, 6)이 팀을 이룰 수 있다. 1, 2, 5는 어느 팀에도 속하지 않는다.

주어진 선택의 결과를 보고 어느 프로젝트 팀에도 속하지 않는 학생들의 수를 계산하는 프로그램을 작성하라.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫 줄에는 학생의 수가 정수 n (2 ≤ n ≤ 100,000)으로 주어진다. 각 테스트 케이스의 둘째 줄에는 선택된 학생들의 번호가 주어진다. (모든 학생들은 1부터 n까지 번호가 부여된다.)

출력

각 테스트 케이스마다 한 줄에 출력하고, 각 줄에는 프로젝트 팀에 속하지 못한 학생들의 수를 나타내면 된다.

예제 입력 1

2

7

3 1 3 7 3 4 6

8

1 2 3 4 5 6 7 8

예제 출력 1

3

0

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
    static BufferedReader br = null;
    static StringTokenizer st = null;
    static int[] map = null;
    static int[] check = null;
    static boolean isCycle;
    static int cycleStartNode;
    static ArrayList<Integer> cycleNode = null;

    public static void dfs(int node, int dfsCnt) {
        int next = map[node];
        if(check[next] == 0) {
            check[next] = dfsCnt;
            dfs(next, dfsCnt);
        }else if(check[next] == dfsCnt) {
            isCycle = true;  // cycleStartNode 나올 때까지 true값 유지
            cycleStartNode = next;
        }

        if(isCycle) {
            cycleNode.add(node);
        }
        if(node == cycleStartNode) {  // 사이클에 포함되는 노드 수집 완료
            isCycle = false;
        }
    }

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

        int T = Integer.parseInt(br.readLine());
        while(T-- > 0) {
            int n = Integer.parseInt(br.readLine());
            map = new int[n + 1];
            check = new int[n + 1];
            st = new StringTokenizer(br.readLine());
            for(int i = 1; i <= n; i++) {
                map[i] = Integer.parseInt(st.nextToken());
            }

            int dfsCnt = 1;  // 이미 센 사이클을 또 세지 않기 위함
            cycleNode = new ArrayList<>();
            for(int i = 1; i <= n; i++) {
                if(check[i] == 0) {
                    check[i] = dfsCnt;
                    dfs(i, dfsCnt);
                    dfsCnt += 1;
                }
            }

            System.out.println(n - cycleNode.size());  // 사이클에 포함되지 못한 노드 개수
            cycleStartNode = 0;  // 초기화
        }
    }
}

 

N 제한이 커서 까다로운 문제.

 

주의할 점,

1. DFS를 돌다가 사이클이 등장한다고 해도 해당 DFS에서 탐색한 모든 노드가 사이클에 포함되지는 않는다. 사이클에 포함되는 노드만 체크할 수 있어야 한다 . (예제의 경우에서 1 -> 3 -> 3 으로 사이클 완성됐지만 1은 포함되지 않음)

2. 사이클을 찾았다고 해도 이전 DFS에서 이미 찾았던 사이클일 수 있다. (예제의 경우에서 5 -> 3 -> 3 으로 사이클을 찾았지만 1 -> 3 -> 3 에서 찾았던 사이클)

 

처음에는 DFS를 한 번 돌고나서 check[]를 초기화하려고 했다. 즉, 모든 노드를 시작점으로 하는 DFS를 한 번 씩 수행하는 것이다.

 

모든 DFS마다 next node == start node인 경우가 나오면 사이클에 해당 DFS의 모든 노드들을 사이클에 포함시키는 것이다.

 

하지만 이 방법은 n제한 때문에 시간초과가 난다.

 

DFS의 시간복잡도는 O(V + E) 이고 이 문제에서 N = V = E로 모두 10만이고, 결국 O(20만) 짜리를 10만번 반복하게 되어O(2 * 10^12)로 시간초과를 맞는다. 

 

 

 

결국 풀지 못하고 정답을 확인했다.

 

이번에도 해답은 check[]에 있었다. dp[]를 dp[][]로 확장하여 사용하는 것과 같은 이 용법에 빨리 익숙해져야 한다.

 

boolean[] check 로 노드의 탐색 여부만을 체크하는 것이 아닌 int[] check 를 사용해서 몇 번째 DFS인지까지 체크한다.

(0 = 탐색한 적 없음, 1 = 1번째 DFS에서 탐색, 2 = 2번째 DFS에서 탐색 ... )

 

여기까지 오면 "주의사항 2" 까지는 해결이 가능하지만 '주의사항 1'이 아직 남아있다.

전역변수 isCycle, cycleStartNode를 통해 "주의사항 1" 까지 해결했다.

 

next가 "이번" DFS에서 이미 방문한 노드라면 해당 노드가 사이클의 시작점이 된다. 

next를 cycleStartNode에 저장하고 재귀됐던 함수들을 하나씩 반환하면서 node == cycleStartNode가 될 때까지 사이클에 포함되는 노드들을 체크한 후 isCycle을 OFF 해주면 정확하게 사이클에 포함된 노드들만 체크할 수 있다.

 

DFS의 원래 시간복잡도인 O(V + E) 로 처리가 가능하다.

www.acmicpc.net/problem/2331

 

2331번: 반복수열

첫째 줄에 반복되는 부분을 제외했을 때, 수열에 남게 되는 수들의 개수를 출력한다.

www.acmicpc.net

문제

다음과 같이 정의된 수열이 있다.

  • D[1] = A
  • D[n] = D[n-1]의 각 자리의 숫자를 P번 곱한 수들의 합

예를 들어 A=57, P=2일 때, 수열 D는 {57, 74(=5^2+7^2=25+49), 65, 61, 37, 58, 89, 145, 42, 20, 4, 16, 37, …}이 된다. 그 뒤에는 앞서 나온 수들(57부터가 아니라 58부터)이 반복된다.

이와 같은 수열을 계속 구하다 보면 언젠가 이와 같은 반복수열이 된다. 이때, 반복되는 부분을 제외했을 때, 수열에 남게 되는 수들의 개수를 구하는 프로그램을 작성하시오. 위의 예에서는 {57, 74, 65, 61}의 네 개의 수가 남게 된다.

입력

첫째 줄에 A(1 ≤ A ≤ 9999), P(1 ≤ P ≤ 5)가 주어진다.

출력

첫째 줄에 반복되는 부분을 제외했을 때, 수열에 남게 되는 수들의 개수를 출력한다.

예제 입력 1

57 2

예제 출력 1

4

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
    static BufferedReader br = null;
    static StringTokenizer st = null;
    static ArrayList<String> list = null;
    static int ans = 0;

    public static void dfs(String num, int p) {
        int nextNum = 0;
        for(int i = 0; i < num.length(); i++) {
            nextNum += Math.pow(num.charAt(i) - '0', p);
        }

        String nextStr = String.valueOf(nextNum);
        if(list.contains(nextStr)) {
            ans = list.indexOf(nextStr);
            return;
        }else {
            list.add(String.valueOf(nextStr));
            dfs(nextStr, p);
        }
    }

    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        st = new StringTokenizer(br.readLine());
        list = new ArrayList<>();

        String a = st.nextToken();
        int p = Integer.parseInt(st.nextToken());
        list.add(a);
        dfs(a, p);
        System.out.println(ans);
    }
}

 

등장했던 수가 또 등장할 때까지 DFS 반복

www.acmicpc.net/problem/10451

 

10451번: 순열 사이클

1부터 N까지 정수 N개로 이루어진 순열을 나타내는 방법은 여러 가지가 있다. 예를 들어, 8개의 수로 이루어진 순열 (3, 2, 7, 8, 1, 4, 5, 6)을 배열을 이용해 표현하면 \(\begin{pmatrix} 1 & 2 &3&4&5&6&7&8 \\  3

www.acmicpc.net

문제

1부터 N까지 정수 N개로 이루어진 순열을 나타내는 방법은 여러 가지가 있다. 예를 들어, 8개의 수로 이루어진 순열 (3, 2, 7, 8, 1, 4, 5, 6)을 배열을 이용해 표현하면 (1234567832781456) 와 같다. 또는, Figure 1과 같이 방향 그래프로 나타낼 수도 있다.

순열을 배열을 이용해 (1…i…nπ1…πi…πn) 로 나타냈다면, i에서 πi로 간선을 이어 그래프로 만들 수 있다.

Figure 1에 나와있는 것 처럼, 순열 그래프 (3, 2, 7, 8, 1, 4, 5, 6) 에는 총 3개의 사이클이 있다. 이러한 사이클을 "순열 사이클" 이라고 한다.

N개의 정수로 이루어진 순열이 주어졌을 때, 순열 사이클의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 순열의 크기 N (2 ≤ N ≤ 1,000)이 주어진다. 둘째 줄에는 순열이 주어지며, 각 정수는 공백으로 구분되어 있다.

출력

각 테스트 케이스마다, 입력으로 주어진 순열에 존재하는 순열 사이클의 개수를 출력한다.

예제 입력 1

2

8

3 2 7 8 1 4 5 6

10

2 1 3 4 5 6 7 9 10 8

예제 출력 1

3

7

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    static BufferedReader br = null;
    static StringTokenizer st = null;
    static int[] map = null;
    static boolean[] check = null;

    public static void dfs(int node) {
        int next = map[node];
        if(!check[next]) {
            check[next] = true;
            dfs(next);
        }
    }

    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());

        while(T-- > 0) {
            int n = Integer.parseInt(br.readLine());
            map = new int[n + 1];
            check = new boolean[n + 1];
            st = new StringTokenizer(br.readLine());
            for(int i = 1; i <= n; i++) {
                map[i] = Integer.parseInt(st.nextToken());
            }

            int cnt = 0;
            for(int i = 1; i <= n; i++) {
                if(!check[i]) {
                    check[i] = true;
                    dfs(i);
                    cnt += 1;
                }
            }
            System.out.println(cnt);
        }
    }
}

 

그냥 DFS 돌리면 된다.

www.acmicpc.net/problem/1707

 

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

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
    static BufferedReader br = null;
    static StringTokenizer st = null;
    static ArrayList<Integer>[] map = null;
    static int[] check = null;

    public static void dfs(int node, int mark) {
        check[node] = mark;
        for(int next : map[node]) {
            if(check[next] == 0) {
                dfs(next, 3 - mark);
            }
        }
    }

    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        int k = Integer.parseInt(br.readLine());

        while(k-- > 0) {
            st = new StringTokenizer(br.readLine());
            int n = Integer.parseInt(st.nextToken());
            int m = Integer.parseInt(st.nextToken());

            map = new ArrayList[n + 1];
            check = new int[n + 1];
            for(int i = 1; i <= n; i++) {
                map[i] = new ArrayList<>();
            }

            while(m-- > 0) {
                st = new StringTokenizer(br.readLine());
                int u = Integer.parseInt(st.nextToken());
                int v = Integer.parseInt(st.nextToken());
                map[u].add(v);
                map[v].add(u);
            }

            for(int i = 1; i <= n; i++) {
                if(check[i] == 0) {
                    dfs(i, 1);
                }
            }

            boolean isBipartite = true;
            for(int i = 1; i <= n; i++) {
                for(int node : map[i]) {
                    if(check[i] == check[node]) {
                        isBipartite = false;
                    }
                }
            }
            System.out.println(isBipartite ? "YES" : "NO");
        }
    }
}

 

기존에 boolean[] 으로 사용하던 check를 int[]로 사용하여 그 쓰임새를 넓혔다.

(마치 int[] dp에서 int[][] dp로 확장시킨 것처럼)

 

이분그래프는 모든 간선을 이루는 두 노드가 서로 다른 진영에 속해야 한다.

 

이를 int[] check를 통해 표시한다.

(check[node] = 0 : 방문 안 함, 1 : 1번 진영, 2 : 2번 진영)

 

일단 DFS를 먼저 실행해준다.

이때, 다음 노드로 넘어갈 때는 항상 서로 다른 진영의 값을 갖도록 한다.

 

탐색을 완료한 후 모든 노드에 대하여 검사를 실시한다.

한 노드와 연결되어있는 다른 모든 노드들은 그 노드와 진영의 값이 달라야 한다.

 

검사 결과에 따라 이분 그래프 여부를 판단한다.

www.acmicpc.net/problem/11724

 

11724번: 연결 요소의 개수

첫째 줄에 정점의 개수 N과 간선의 개수 M이 주어진다. (1 ≤ N ≤ 1,000, 0 ≤ M ≤ N×(N-1)/2) 둘째 줄부터 M개의 줄에 간선의 양 끝점 u와 v가 주어진다. (1 ≤ u, v ≤ N, u ≠ v) 같은 간선은 한 번만 주

www.acmicpc.net

문제

방향 없는 그래프가 주어졌을 때, 연결 요소 (Connected Component)의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 정점의 개수 N과 간선의 개수 M이 주어진다. (1 ≤ N ≤ 1,000, 0 ≤ M ≤ N×(N-1)/2) 둘째 줄부터 M개의 줄에 간선의 양 끝점 u와 v가 주어진다. (1 ≤ u, v ≤ N, u ≠ v) 같은 간선은 한 번만 주어진다.

출력

첫째 줄에 연결 요소의 개수를 출력한다.

예제 입력 1

6 5

1 2

2 5

5 1

3 4

4 6

예제 출력 1

2

예제 입력 2

6 8

1 2

2 5

5 1

3 4

4 6

5 4

2 4

2 3

예제 출력 2

1

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
    static BufferedReader br = null;
    static StringTokenizer st = null;
    static ArrayList<Integer>[] map = null;
    static boolean[] check = null;

    public static void dfs(int node) {
        check[node] = true;
        for(int next : map[node]) {
            if(!check[next]) {
                dfs(next);
            }
        }
    }

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

        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());

        map = new ArrayList[n + 1];
        check = new boolean[n + 1];

        for(int i = 1; i <= n; i++) {
            map[i] = new ArrayList<>();
        }

        while(m-- > 0) {
            st = new StringTokenizer(br.readLine());
            int u = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            map[u].add(v);
            map[v].add(u);
        }

        int cnt = 0;
        for(int i = 1; i <= n; i++) {
            if(!check[i]) {
                dfs(i);
                cnt += 1;
            }
        }
        System.out.println(cnt);
    }
}

www.acmicpc.net/problem/1260

 

1260번: DFS와 BFS

첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사

www.acmicpc.net

문제

그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오. 단, 방문할 수 있는 정점이 여러 개인 경우에는 정점 번호가 작은 것을 먼저 방문하고, 더 이상 방문할 수 있는 점이 없는 경우 종료한다. 정점 번호는 1번부터 N번까지이다.

입력

첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사이에 여러 개의 간선이 있을 수 있다. 입력으로 주어지는 간선은 양방향이다.

출력

첫째 줄에 DFS를 수행한 결과를, 그 다음 줄에는 BFS를 수행한 결과를 출력한다. V부터 방문된 점을 순서대로 출력하면 된다.

예제 입력 1 복사

4 5 1

1 2

1 3

1 4

2 4

3 4

예제 출력 1

1 2 4 3

1 2 3 4

예제 입력 2

5 5 3

5 4

5 2

1 2

3 4

3 1

예제 출력 2

3 1 2 5 4

3 1 4 2 5

예제 입력 3

1000 1 1000

999 1000

예제 출력 3 복사

1000 999

1000 999

 

 

 

 

 

 

풀이 .

import java.io.*;
import java.util.*;

public class Main {
    static StringBuilder sb = null;

    public static void dfs(int node, ArrayList<Integer>[] map, boolean[] check) {
        check[node] = true;
        sb.append(node + " ");

        for(int i = 0; i < map[node].size(); i++) {
            int next = map[node].get(i);
            if(!check[next]) {
                dfs(next, map, check);
            }
        }
    }

    public static void bfs(int start, ArrayList<Integer>[] map, boolean[] check) {
        check[start] = true;
        sb.append(start + " ");

        Queue<Integer> que = new ArrayDeque<>();
        que.add(start);

        while(!que.isEmpty()) {
            int now = que.poll();
            for(int i = 0; i < map[now].size(); i++) {
                int next = map[now].get(i);
                if(!check[next]) {
                    que.add(next);
                    sb.append(next + " ");
                    check[next] = true;
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        sb = new StringBuilder();
        StringTokenizer st = new StringTokenizer(br.readLine());

        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());
        int start = Integer.parseInt(st.nextToken());

        ArrayList<Integer>[] map = new ArrayList[n + 1];
        for(int i = 1; i <= n; i++) {
            map[i] = new ArrayList<>();
        }

        boolean[] check = new boolean[n + 1];
        while(m-- > 0) {
            st = new StringTokenizer(br.readLine());
            int u = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            map[u].add(v);
            map[v].add(u);
        }

        for(int i = 1; i <= n; i++) {
            Collections.sort(map[i]);
        }

        dfs(start, map, check);
        sb.append("\n");

        check = new boolean[n + 1];  // 초기화
        bfs(start, map, check);

        bw.write(sb.toString());
        br.close();
        bw.flush();
        bw.close();
    }
}

 

그냥 DFS, BFS 짜면 된다.

 

사실 완벽한 코드는 아니다.

 

모든 노드가 연결되어있다는 보장이 없기 때문에 main 안에서도 dfs, bfs를 반복 호출 해줘야 한다.

 

운이 좋게 모든 테스트 케이스가 연결된 그래프였나보다.

+ Recent posts