반응형

위상정렬 (Topological Sort) 의 가장 대표적인 문제


위상정렬을 처음 이해하고 문제를 푸는데 어려웠다. 머리속에 문제를 이해는 했는데 코드는 잘 안짜지는 느낌?


풀이

1. 값을 저장해준다. List를 이용하여. 

2. indegree가 0인 값을 큐에 모두 집어 넣는다.

3. 큐가 빌때까지 0인 값을 하나씩 빼서 그 다음 값을 다시 큐에 집어 넣는다. (단 그때 화살표 값인 Indegree를 하나씩 줄인다.)

4. 끝


의 과정 반복이다.

문제가 안풀리면 위상정렬을 공부하고 다시 보면 될것이다.

맞다. 이문제는 PriorityQueue를 사용해야한다. 왜냐하면 Queue에 같이 들어있을 때, 쉬운문제(번호가 작은 순)으로 풀어야 하기 때문

Queue를 사용하면 선입선출이기 때문에 값이 다르게 나온다.


소스

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
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(new FileInputStream("input.txt"));
        int N = sc.nextInt();
        int M = sc.nextInt();
        int[] indegree = new int[N+1];
        ArrayList<Integer>[] list = new ArrayList[N+1];    //LinkedList 사용해도 상관 없음
        for(int i=1; i<=N; i++){
            list[i] = new ArrayList<Integer>();
        }
        for(int i=0; i<M; i++){
            int x = sc.nextInt();
            int y = sc.nextInt();
            list[x].add(y);    //리스트 안의 리스트에 값을 넣어준다.
            indegree[y]++;    //자신을 가르키고 있는 화살표의 갯수
        }
        PriorityQueue<Integer> q = new PriorityQueue<Integer>();
        
        for(int i=1; i<=N; i++){
            //indegree가 0인 값들 모두 큐에 넣어준다.
            if(indegree[i]==0){
                q.add(i);
            }
        }
        while(!q.isEmpty()){
            //indgree가 0인 값을 큐에서 뽑는다.
            int current = q.poll();
            System.out.print(current+" ");
            //뽑힌 곳에서 갈 수 있는 곳들을 검색하여 indegree를 -1한다.(자신을 가르키는 화살표가 하나 사라졌기 때문에)
            for(int i=0; i<list[current].size(); i++){
                int next = list[current].get(i);
                indegree[next]--;
                //indegree가 0이라면 큐에 넣는다.
                if(indegree[next]==0){
                    q.add(next);
                }
            }
        }
    }
 
}
cs


반응형
반응형

설명도 필요없는 문제

근데 합격률이 극악인 이유는 문제가 제대로 명시되지 않았기 때문에...

동점일 경우 어떻게 출력되어야 하는지 나와있지 않음.


풀이

1. 영식이는 30분 마다 이므로 나누기 30 으로 계산 후 10원 청구이므로 곱하기 10

1. 민식이는 60분 마다 이므로 나누기 60 으로 계산 후 15원 청구이므로 곱하기 15


코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.Scanner;
 
public class Main {
 
    public static void main(String args[]) throws Exception {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int K;
        int YoungSik = 0, MinSik = 0;
        for (int i = 0; i < N; i++) {
            K = sc.nextInt();
            YoungSik += ((K / 30+ 1* 10;
            MinSik += ((K / 60+ 1* 15;
 
        }
        if (YoungSik == MinSik) {
            System.out.println("Y M " + YoungSik);
        } else if (YoungSik < MinSik) {
            System.out.println("Y " + YoungSik);
        } else if (YoungSik > MinSik) {
            System.out.println("M " + MinSik);
        }
    }
}
cs


반응형
반응형

BFS? DFS?


알고리즘 분류에는 DFS도 나와있는데, DFS로는 어떻게 풀지 모르겠다. 

DFS로 푸니까 스택오버플로우가.....................................

므즈건 BFS로 푸는게 나을거 같다.


풀때는 굉장히 어려운 문제였는데 풀고나니까 쉬워보인다. 그렇게 어려운 문제는 아님;


풀이

1. 다음에 이동할 위치 앞으로 한칸 (+1), 뒤로 한칸 (-1), 순간이동 (x2) 을 생각해준다.

2. 조건에 맞는지 확인한다. 조건이란 배열을 벗어나지 않았는지, 이전에 방문했던점이 아닌지 이다. 모든 배열을 -1로 놓고 변하지 않았다면 이동 X

선입선출이므로 해당 위치에 먼저 도착한놈이 무조건 빠르거나 같다. (이동 횟수가 작다) 그렇기 때문에 이전에 방문했던점이면 굳이 갈 필요가 없다.

나는 이조건에서 헤맴..

3. 조건에 맞다면 이동할 위치 3개로 모두 이동한다. (큐를 이용한다.)

4. 큐에서 다시 하나씩 빼가면서 도착할 때 까지 반복한다.


코드

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
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
 
public class Main {
    public static void main(String args[]) throws Exception {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int K = sc.nextInt();
        int[] Min = new int[100005];
        Arrays.fill(Min, -1);    //초기값을 다 -1로 설정
        System.out.println(BFS(N, K, Min));
 
    }
 
    public static int BFS(int N, int K, int[] Min) {
        int nextN = N;
        int[] status = new int[3];
        Queue<Integer> q = new LinkedList<Integer>();
        q.add(nextN);
        Min[nextN] = 0;
 
        while (!q.isEmpty() && nextN != K) {
 
            nextN = q.poll();
            //다음에 이동할 좌표들
            status[0= nextN - 1;     //뒤로 한칸
            status[1= nextN + 1;    //앞으로 한칸
            status[2= nextN * 2;    //순간이동
 
            for (int i = 0; i < 3; i++) {
                //배열을 벗어나지 않았는지 확인
                if (status[i] >= 0 && status[i] <= 100000) {
                    //이전에 방문했는지 확인
                    if (Min[status[i]] == -1) {
                        //처음 간 곳이라면 큐에 넣고 상태를 전 위치값 +1 을 해준다.
                        q.add(status[i]);
                        Min[status[i]] = Min[nextN] + 1;
 
                    }
                }
            }
        }
        return Min[K];
    }
}
cs


반응형
반응형

1. 가장 처음 시작하는 시간과 가장 마지막에 끝나는 시간을 저장한다.

2. 그 시간동안 몇명이 들어와있는지 배열에 카운트 한다.

3. 개장 시작부터 마감시간 까지 파악하여 1일 경우 x1을  2일경우 x2를 3일경우 x3을 하여 더한다.


아래 사진은 카운트 예시이다.


arr[1] 은 트럭 한대 이기 때문에 +1이 arr[2]는 두대가 들어왔기 때문에 +2 arr[3]은 트럭 3대가 들어왔기 때문에 +3 의 값을 갖고 있다.

Switch 문을 통해 1,2,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
import java.util.Scanner;
 
class Main {
    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
 
        int A = sc.nextInt();
        int B = sc.nextInt();
        int C = sc.nextInt();
        int[] arr = new int[100];
        int start, end, max = 0;
        int min = 0;
        int sum = 0;
        for (int i = 0; i < 3; i++) {
            start = sc.nextInt();
            end = sc.nextInt();
            min = Math.min(min, start); //가장 빨리 시작하는 시간
            max = Math.max(max, end); //가장 늦게 끝나는 시간
            
            //트럭 한대의 start ~ end 시간동안 배열을 +1 해준다. 
            for (int j = start; j < end; j++) {
                arr[j]++;
            }
        }
        // 가장 처음 들어온 시간 부터 가장 마지막 시간 까지 계산을 한다.
        for (int i = min; i < max; i++) {
            switch (arr[i]) {
            case 1:
                sum = sum + A*arr[i];
                break;
            case 2:
                sum = sum + B*arr[i];
                break;
            case 3:
                sum = sum + C*arr[i];
                break;
            }
        }
        System.out.println(sum);
    }
 
}
cs


반응형
반응형

윾기농 배추 문제

맨처음 런타임 에러가 나길래 뭐지 하고 문제를 다시 보니까

배추밭이 N*N이 아니라 N*M 이더라.... 

호다닥 수정하고 나니 정답!

+ BufferedReader를 사용했는데 String[] 배열을 통해서 값을 받아오는것 밖에 없나 싶더라.


풀이

1. 좌표 (0,0) 부터 (N,N) 까지 하나씩 살펴본다.

2. 배추가 있을경우(1일경우) DFS , BFS를 사용하여 상,하,좌,우에 배추도 같이 제거한다. (붙어있다면 한번에 제거 할 수 있기 때문)

3. 한번 수확하러 들어갈때마다 +1 씩 더해준다. (주변에 있는 배추 수확은 덧셈을 안해도 된다.)



소스

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
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
 
class Main {
    static int[] dx = { -1010 };
    static int[] dy = { 010-1 };
    static int[][] arr;
    static int N;
    static int M;
 
    public static void main(String[] args) throws Exception {
        //BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("input.txt")));
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 
        int T = Integer.parseInt(br.readLine());
        for (int Testcase = 0; Testcase < T; Testcase++) {
            String str[] = br.readLine().split(" ");
            M = Integer.parseInt(str[0]);
            N = Integer.parseInt(str[1]);
            int K = Integer.parseInt(str[2]);
            int count = 0;
            arr = new int[N][M];
            for (int i = 0; i < K; i++) {
                str = br.readLine().split(" ");
                arr[Integer.parseInt(str[1])][Integer.parseInt(str[0])] = 1;
            }
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < M; j++) {
                    if (arr[i][j] != 0) {
                        DFS(i, j);
                        //배추 수확
                        count++;
                    }
                }
            }
 
            System.out.println(count);
 
        }
    }
 
    public static void DFS(int X, int Y) {
 
        for (int i = 0; i < 4; i++) {
            //다음 방문지 nextX,와 nextY
            int nextX = X + dx[i];
            int nextY = Y + dy[i];
 
            //nextX, nextY가 범위를 벗어난다면 그냥 통과한다.
            if (nextX < 0 || nextY < 0 || nextX >= N || nextY >= M) {
                continue;
            }
            //다음 방문할 값이 0 이라면 그냥 통과한다.
            if (arr[nextX][nextY] == 0) {
                continue;
            }
            //방문한점은 0으로 바꿔준다.
            arr[nextX][nextY] = 0;
            DFS(nextX, nextY);
        }
    }
 
}
cs


반응형
반응형

6,9를 제외한 다른 숫자는 배열 카운트로 갯수를 저장하면된다.

6,9가 문제가 되는데 이때 6,9를 같은 숫자로 가정하여 계산을 한다.

6,9를 합쳐 반으로 나누면 되는데 합이 홀수 일때는 +1 을 해줘야한다.

예를들어) 6이 5번 9가 8번 사용하였을 때 둘의 합은 13이 되고 2로 나눌 경우 6이 되버린다.(정수이기 때문에)

             그래서 1을 더해주면 된다.



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
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
 
class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("input.txt")));
 
        String str = br.readLine();
 
        int size = str.length();
        int[] arr = new int[10];
        int temp = 0;
        int max = 0;
 
        //counting 배열을 사용하였다.
        for (int i = 0; i < size; i++) {
            temp = str.charAt(i) - '0';
            arr[temp]++;
 
        }
        //다른 숫자는 상관없지만 6,9일땐 바꿔서 사용가능하다.
        //6,9를 같은 숫자로 본다.
        int k = (arr[6+ arr[9]);
        //6,9의 합이 짝수이면 반으로 나누면 된다.
        if (k % 2 == 0) {
            arr[6= k / 2;
            arr[9= k / 2;
        }
        //6,9의 합이 홀수이면 반으로 나눠도 1번 더 사용해야되기 때문에 1을 더해준다.
        else {
            arr[6= k / 2 + 1;
            arr[9= k / 2 + 1;
        }
        //반복해서 최대값을 찾는다.
        for (int i : arr) {
            max = Math.max(max, i);
        }
        System.out.println(max);
    }
 
}
cs


반응형
반응형

단순 BFS 문제이다. 

BFS 문제로는 어렵지 않다.

근데 나는 DFS로 풀고 싶은데 시간초과 안나게 어떻게 해야할지 모르겠다...

그리고 헷갈리는건 +1만 해주면 끝일까?  Queue를 이용하기 때문에 먼저 방문한게 조금더 최단거리일려나? 음음


BFS 해결방법

1. 다음 방문할 점을 큐에 넣는다.

2. 큐에서 빼온다음 다음 갈 곳이 조건에 벗어나지 않는다면 큐에 넣는다.

3. 큐가 빌때까지 계속한다. ( 내가 원하는 점에 왔을때 return 해줘도 가능하지 않을까? 개인적인 생각)


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
73
import java.io.FileInputStream;
import java.util.*;
 
public class Main {
 
    static int[][] arr;
    static boolean[][] visited;
    static int[] dx = { -1010 };
    static int[] dy = { 0-101 };
    static int N;
    static int M;
 
    public static void main(String args[]) throws Exception {
        // Scanner sc = new Scanner(System.in);
        Scanner sc = new Scanner(new FileInputStream("input.txt"));
 
        N = sc.nextInt();
        M = sc.nextInt();
        sc.nextLine();
        arr = new int[N][M];
        visited = new boolean[N][M];
        for (int i = 0; i < N; i++) {
            String str = sc.nextLine();
            for (int j = 0; j < M; j++) {
                arr[i][j] = str.charAt(j)-'0';
                visited[i][j] = false;
            }
        }
        visited[0][0= true;
        BFS(00);
        System.out.println(arr[N - 1][M - 1]);
    }
 
    static public void BFS(int x, int y) {
 
        Queue<Dot> q = new LinkedList<Dot>();
        q.add(new Dot(x, y));
        //큐가 끝날때 까지
        while (!q.isEmpty()) {
            Dot d = q.poll();
            for (int i = 0; i < 4; i++) {
                //다음 방문할 좌표 nextX, nextY
                int nextX = d.x + dx[i];
                int nextY = d.y + dy[i];
                
                //다음 좌표가 범위를 넘어갈때 건너뛰기
                if (nextX < 0 || nextY < 0 || nextX >= N || nextY >= M) {
                    continue;
                }
                //이미 방문했던 점이면 건너뛰기
                if (visited[nextX][nextY] || arr[nextX][nextY] == 0) {
                    continue;
                }
                //다음에 방문할 좌표를 큐에 넣는다.
                q.add(new Dot(nextX, nextY));
                //배열안에 다음 방문할 곳은 현재 방문했던 점보다 1칸 더 가야하므로 +1
                arr[nextX][nextY] = arr[d.x][d.y] + 1;
                //다음 좌표는 방문했음으로 표시
                visited[nextX][nextY] = true;
            }
        }
    }
}
 
class Dot {
    int x;
    int y;
 
    Dot(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
cs


반응형
반응형

1. A,B,C의 입력과 나머지 입력의 차이점만 알면 쉽게 풀 수 있다.


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
import java.io.FileInputStream;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(new FileInputStream("input.txt"));
        String str = sc.next();
 
        int size = str.length();
        int[] arr = new int[size];
        int[] decrypt = new int[size];
        for (int i = 0; i < size; i++) {
            arr[i] = str.charAt(i);
            //A,B,C의 입력은 X,Y,Z로 만들어 줘야하는데 앞으로 3칸을 땡기면 이상한 값이 출력방지하기 위해 + 23을 해준다.
            if(arr[i]-68<0){
                System.out.print((char)(arr[i]+23));
            }
            //ABC이외의 값들은 앞으로 3칸만 옮기면 된다.
            else{
                System.out.print((char)(arr[i]-3));
            }
            
        
        }
 
    }
 
}
 
cs


반응형
반응형

정말 단순하면서 어려웠던 문제..


입력의 값이 크지 않기 때문에 반복문을 돌려도 된다.


1. 5로 나눠질때까지 계속 해서 3을 빼주면 된다. 또는 3으로 빼가면서 크기가 0보다 같거나 작아지면 종료한다.

2. 만약 처음값이 0보다 작은 값이면, 5던지 3이던지 나눠질 수 없는 값이다. 그런경우 -1을 출력한다.



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
import java.io.FileInputStream;
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(new FileInputStream("input.txt"));
        // Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int five = 0;
        int three = 0;
        
        
        while(N%5!=0&&N>=0){
            N-=3;
            three++;
        }
        if(N<0){
            System.out.println(-1);
        }
        else{
            five = N/5;
            System.out.println(five+three);        
        }
    
    }
 
}
 
cs


반응형
반응형

전체 탐색으로 하면 시간 초과가 날 것 같아서 HashSet를 사용했다.

또한, 중복된 수가 없었기 때문에 HashSet 사용이 가능했다.


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
import java.io.FileInputStream;
import java.util.HashSet;
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(new FileInputStream("input.txt"));
        // Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        HashSet<Integer> set = new HashSet<Integer>();
        for (int i = 0; i < N; i++) {
            set.add(sc.nextInt());
        }
 
        int M = sc.nextInt();
        for (int i = 0; i < M; i++) {
            if (set.contains(sc.nextInt())) {
                System.out.print(1);
            } else {
                System.out.print(0);
            }
            System.out.print(" ");
        }
    }
 
}
 
cs


반응형

+ Recent posts