www.acmicpc.net/problem/2252

 

2252번: 줄 세우기

첫째 줄에 N(1≤N≤32,000), M(1≤M≤100,000)이 주어진다. M은 키를 비교한 회수이다. 다음 M개의 줄에는 키를 비교한 두 학생의 번호 A, B가 주어진다. 이는 학생 A가 학생 B의 앞에 서야 한다는 의미이

www.acmicpc.net

자신보다 뒤에 서야하는 학생의 번호를 list에 넣습니다.

그리고 뒤에 서야하는 학생의 번호는 conn 배열을 이용하여 자신보다 앞에 서야하는 학생이 몇명인지 유지합니다.

 

그 다음 conn[i]이 0인 학생들의 번호만 큐에 추가한 후에 bfs를 돌립니다.

 

먼저 번호 x보다 뒤에 서야하는 번호를 하나씩 확인하여 conn[y]--를 해줍니다.

conn[y]=0이 되면 자신보다 앞에 있어야할 번호를 모두 탐색을 했으므로 y를 큐에 추가합니다.

이런 방식으로 ans에 번호를 차례대로 쌓는 방식입니다.

 

이 문제는 줄을 못 세우는 경우가 없기 때문에 ans의 크기가 N보다 작은지 확인하는 예외처리를 하지 않았습니다.

만약 문제에서 이런 경우는 요구하면 무조건 해줘야하는 예외케이스 입니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static StringBuffer sb = new StringBuffer();
    static ArrayList<Integer> list[] = new ArrayList[32001];
    static ArrayList<Integer> ans = new ArrayList<>();
    static int conn[] = new int[32001];
    static int N, M;
 
    static void print() {
        for (int i = 0; i < ans.size(); i++) {
            sb.append(ans.get(i) + " ");
        }
        System.out.println(sb.toString());
    }
 
    static void func() {
        Queue<Integer> q = new LinkedList<>();
        for (int i = 1; i <= N; i++) {
            if (conn[i] == 0) {
                q.add(i);
            }
        }
 
        while (!q.isEmpty()) {
            int x = q.poll();
 
            ans.add(x);
            for (int i = 0; i < list[x].size(); i++) {
                int y = list[x].get(i);
 
                conn[y]--;
 
                if (conn[y] == 0)
                    q.add(y);
            }
        }
    }
 
    static void input() throws Exception {
        int u, v;
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        for (int i = 1; i <= N; i++)
            list[i] = new ArrayList<>();
 
        while (M-- > 0) {
            st = new StringTokenizer(br.readLine());
            u = Integer.parseInt(st.nextToken());
            v = Integer.parseInt(st.nextToken());
            list[u].add(v);
            conn[v]++;
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
        print();
    }
}
cs

'algorithm > Topological-sort' 카테고리의 다른 글

boj 23059 리그 오브 레게노  (0) 2021.12.15

www.acmicpc.net/problem/1717

 

1717번: 집합의 표현

첫째 줄에 n(1 ≤ n ≤ 1,000,000), m(1 ≤ m ≤ 100,000)이 주어진다. m은 입력으로 주어지는 연산의 개수이다. 다음 m개의 줄에는 각각의 연산이 주어진다. 합집합은 0 a b의 형태로 입력이 주어진다. 이는

www.acmicpc.net

union-find를 사용해볼 수 있는 문제입니다.

 

합집합 연산은 0 a b 형태로 주어지고, a가 포함되어 있는 집합과 b가 포함되어 있는 집합을 합친다는 의미입니다.

두 집합이 같은 집합인지 확인하는 연산은 1 a b 형태로 주어지고, a와 b가 같은 집합이면 YES, 아니면 NO를 출력하는 문제입니다.

 

저는 일단 parent배열에 집합의 루트를 자신으로 저장해놓고, union_find를 통해 a의 루트와 b의 루트를 찾아서

합치거나, 같은 집합인지 확인하였습니다.

 

 

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.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static int parent[] = new int[1000001];
    static int N, M;
 
    static int find(int v) {
        if (parent[v] == v)
            return v;
        return parent[v] = find(parent[v]);
    }
 
    static void union(int u, int v) {
        int a = find(u);
        int b = find(v);
 
        if (parent[a] != parent[b])
            parent[b] = parent[a];
    }
 
    static void func() throws Exception {
        StringBuffer sb = new StringBuffer();
        int type, u, v;
        while (M-- > 0) {
            st = new StringTokenizer(br.readLine());
            type = Integer.parseInt(st.nextToken());
            u = Integer.parseInt(st.nextToken());
            v = Integer.parseInt(st.nextToken());
 
            if (type == 0)
                union(Math.min(u, v), Math.max(u, v));
            else {
                if (find(u) == find(v))
                    sb.append("YES\n");
                else
                    sb.append("NO\n");
            }
        }
        
        System.out.print(sb.toString());
    }
 
    static void init() {
        for (int i = 1; i <= N; i++) {
            parent[i] = i;
        }
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
    }
 
    public static void main(String[] args) throws Exception {
        input();
        init();
        func();
    }
}
cs

'algorithm > Union-Find' 카테고리의 다른 글

boj 20040 사이클 게임  (0) 2021.06.27
boj 1043 거짓말  (0) 2021.04.05
boj 10775 공항  (0) 2021.03.17
boj 4195 친구 네트워크  (0) 2021.03.17
boj 1976 여행 가자  (0) 2021.03.17

www.acmicpc.net/problem/5569

 

5569번: 출근 경로

상근이가 사는 도시는 남북 방향으로 도로가 w개, 동서 방향으로 도로가 h개 있다.  남북 방향 도로는 서쪽부터 순서대로 번호가 1, 2, ..., w로 매겨져 있다. 또, 동서 방향 도로는 남쪽부터 순서대

www.acmicpc.net

저는 4차원배열로 dp를 구성하였습니다.

 

dp[x][y][t][chk]

x, y 좌표

t : 현재 진행방향 (0 -> x / 1 -> y)

chk : 방향 변경 가능 여부 (0 -> 변경 불가능 / 1 -> 변경 가능)

 

현재 진행 방향에서 chk = 0이면 현재 진행방향으로 이동해야합니다.

chk = 1이면 현재 진행방향, 다른 방향 모두 탐색합니다.

 

모든 경우의 수를 계산하여 100000으로 나눈 나머지를 출력합니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static final int MOD = 100000;
    static int dp[][][][];
    static int N, M;
 
    static int func(int x, int y, int t, int chk) {
        if (x <= 0 || y <= 0 || x > N || y > M)
            return 0;
 
        if (x == N && y == M)
            return dp[x][y][t][chk] = 1;
 
        if (dp[x][y][t][chk] != -1)
            return dp[x][y][t][chk];
 
        dp[x][y][t][chk] = 0;
        if (t == 1) {
            if (chk == 1) {
                dp[x][y][t][chk] = (dp[x][y][t][chk] + func(x, y + 1, t, chk) + func(x + 1, y, 1 - t, 1 - chk)) % MOD;
            } else {
                dp[x][y][t][chk] = (dp[x][y][t][chk] + func(x, y + 1, t, 1 - chk)) % MOD;
            }
        } else {
            if (chk == 1) {
                dp[x][y][t][chk] = (dp[x][y][t][chk] + func(x + 1, y, t, chk) + func(x, y + 11 - t, 1 - chk)) % MOD;
            } else {
                dp[x][y][t][chk] = (dp[x][y][t][chk] + func(x + 1, y, t, 1 - chk)) % MOD;
            }
        }
 
        return dp[x][y][t][chk];
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        dp = new int[N + 1][M + 1][2][2];
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= M; j++) {
                Arrays.fill(dp[i][j][0], -1);
                Arrays.fill(dp[i][j][1], -1);
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        System.out.println((func(1100+ func(1110)) % MOD);
    }
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 10211 Maximum Subarray  (0) 2021.02.18
boj 10826 피보나치 수 4  (0) 2021.02.08
boj 1010 다리 놓기  (0) 2021.02.05
boj 5557 1학년  (0) 2021.02.05
boj 5573 산책  (0) 2021.02.04

www.acmicpc.net/problem/1010

 

1010번: 다리 놓기

입력의 첫 줄에는 테스트 케이스의 개수 T가 주어진다. 그 다음 줄부터 각각의 테스트케이스에 대해 강의 서쪽과 동쪽에 있는 사이트의 개수 정수 N, M (0 < N ≤ M < 30)이 주어진다.

www.acmicpc.net

이항계수 공식을 이용하는 문제입니다.

dp[K][N] = kCn으로 하였고, kCn = (k-1)C(n-1)+(k-1)C(n)의 공식을 이용하면 풀리는 문제입니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main{
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static StringBuffer sb = new StringBuffer();
    static int dp[][] = new int[31][31];
    static int N, M;
 
    static void init() {
        for (int i = 1; i <= 30; i++) {
            dp[i][0= 1;
            dp[0][i] = 1;
        }
 
        for (int i = 1; i <= 30; i++) {
            for (int j = 1; j <= i; j++) {
                dp[i][j] = dp[i - 1][j - 1+ dp[i - 1][j];
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        init();
        st = new StringTokenizer(br.readLine());
        int tc = Integer.parseInt(st.nextToken());
        int N, K;
        while (tc-- > 0) {
            st = new StringTokenizer(br.readLine());
            N = Integer.parseInt(st.nextToken());
            K = Integer.parseInt(st.nextToken());
            sb.append(dp[K][N] + "\n");
        }
 
        System.out.println(sb.toString());
    }
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 10826 피보나치 수 4  (0) 2021.02.08
boj 5569 출근 경로  (0) 2021.02.06
boj 5557 1학년  (0) 2021.02.05
boj 5573 산책  (0) 2021.02.04
boj 17528 Two Machines  (0) 2021.01.28

www.acmicpc.net/problem/1918

 

1918번: 후위 표기식

첫째 줄에 중위 표기식이 주어진다. 단 이 수식의 피연산자는 A~Z의 문자로 이루어지며 수식에서 한 번씩만 등장한다. 그리고 -A+B와 같이 -가 가장 앞에 오거나 AB와 같이 *가 생략되는 등의 수식

www.acmicpc.net

입력은 중위 표기식으로 주어지고 후위 표기식으로 출력하는 문제입니다.

 

우선 A ~ Z까지의 문자는 바로 출력입니다.

'('는 스택에 바로 push하시면 되고

')'가 나오면 스택에 '('가 나올때까지 pop한 것을 출력해줍니다.

+, -가 나오면 자신보다 우선순위가 낮은 연산자가 없으므로 괄호를 만날때까지 pop한 것을 출력해줍니다.

*, /가 나오면 자신보다 우선순위가 낮은 +, -가 나오거나 괄호를 만날때까지 pop한 것을 출력해줍니다.

마지막에 남아있는 연산자를 모두 출력합니다.

 

 

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.BufferedReader;
import java.io.InputStreamReader;
import java.util.Stack;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static StringBuffer sb = new StringBuffer();
    static Stack<Character> s = new Stack<>();
    static char ch[];
 
    static void func() {
        for (char x : ch) {
            if ('A' <= x && x <= 'Z')
                sb.append(x);
            else if (x == '(')
                s.push(x);
            else if (x == ')') {
                while (s.peek() != '(')
                    sb.append(s.pop());
                s.pop();
            } else if (x == '+' || x == '-') {
                while (!s.isEmpty() && s.peek() != '(')
                    sb.append(s.pop());
                s.push(x);
            } else {
                while (!s.isEmpty() && (s.peek() == '*' || s.peek() == '/'))
                    sb.append(s.pop());
                s.push(x);
            }
        }
 
        while (!s.isEmpty())
            sb.append(s.pop());
 
        System.out.println(sb.toString());
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        ch = st.nextToken().toCharArray();
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

'algorithm > data-structure' 카테고리의 다른 글

boj 9372 상근이의 여행  (0) 2021.02.09
boj 1158 요세푸스 문제  (0) 2021.02.09
boj 1935 후위 표기식2  (0) 2021.02.05
boj 2493 탑  (0) 2021.02.04
boj 6416 트리인가?  (0) 2021.02.04

www.acmicpc.net/problem/1935

 

1935번: 후위 표기식2

첫째 줄에 피연산자의 개수(1 ≤ N ≤ 26) 가 주어진다. 그리고 둘째 줄에는 후위 표기식이 주어진다. (여기서 피연산자는 A~Z의 영대문자이며, A부터 순서대로 N개의 영대문자만이 사용되며, 길이

www.acmicpc.net

피연산자가 문자로 주어진 후위표기식이 입력으로 들어오면 이를 계산한 결과를 소수 둘째 자리까지 출력하는 문제입니다.

우선 피연산자에 대응하는 값은 alphabet 배열에 넣어서 alphabet[ch-'A']와 같이 사용하였습니다.

 

A ~ Z가 오면 스택에 대응하는 값을 넣고, 연산자가 오면 두개를 꺼내서 계산한 값을 스택에 넣었습니다.

마지막에 스택에 들어있는 값은 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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Stack;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static Stack<Double> s = new Stack<>();
    static char ch[];
    static double alphabet[] = new double[26];
    static int N;
 
    static void func() {
        for (char x : ch) {
            if ('A' <= x && x <= 'Z')
                s.push(alphabet[x - 'A']);
            else if (x == '+') {
                double a = s.pop();
                double b = s.pop();
                s.push(b + a);
            } else if (x == '-') {
                double a = s.pop();
                double b = s.pop();
                s.push(b - a);
            } else if (x == '*') {
                double a = s.pop();
                double b = s.pop();
                s.push(b * a);
            } else {
                double a = s.pop();
                double b = s.pop();
                s.push(b / a);
            }
        }
 
        System.out.printf("%.2f\n", s.pop());
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
 
        st = new StringTokenizer(br.readLine());
        ch = st.nextToken().toCharArray();
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            alphabet[i] = Integer.parseInt(st.nextToken());
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

'algorithm > data-structure' 카테고리의 다른 글

boj 1158 요세푸스 문제  (0) 2021.02.09
boj 1918 후위 표기식  (0) 2021.02.05
boj 2493 탑  (0) 2021.02.04
boj 6416 트리인가?  (0) 2021.02.04
boj 3190 뱀  (0) 2021.02.02

www.acmicpc.net/problem/5557

 

5557번: 1학년

상근이가 1학년 때, 덧셈, 뺄셈을 매우 좋아했다. 상근이는 숫자가 줄 지어있는 것을 보기만 하면, 마지막 두 숫자 사이에 '='을 넣고, 나머지 숫자 사이에는 '+' 또는 '-'를 넣어 등식을 만들며 놀

www.acmicpc.net

조합과 dp를 이용하여 해결하였습니다.

 

0 ~ N - 2를 조합하여 N - 1번째 값이 나오는 갯수를 출력하는 문제입니다.

단, 더하거나 빼는 과정에서 음수나 20보다 커지면 안됩니다.

저는 배열을 dp[idx][now] => (현재 idx에서 값이 now일 경우의 수)

 

0번 인덱스의 값은 무조건 +로 들어가니 그 다음인 1번 인덱스와, list[0]으로 재귀를 돌려줍니다.

now + list[idx] <= 20 일 경우에만 더한 값을 다음으로 넘겨주고

now - list[idx]>=0 일 경우에만 뺀 값을 다음으로 넘겨줍니다.

 

인덱스가 N - 1이 되면 지금까지 구한 값이 list[N - 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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static long dp[][];
    static int N, list[];
 
    static long func(int idx, int now) {
        if (idx == N - 1) {
            if (now == list[idx])
                return dp[idx][now] = 1;
            return dp[idx][now] = 0;
        }
 
        if (dp[idx][now] != -1)
            return dp[idx][now];
 
        dp[idx][now] = 0;
 
        if (now + list[idx] <= 20)
            dp[idx][now] += func(idx + 1, now + list[idx]);
 
        if (now - list[idx] >= 0)
            dp[idx][now] += func(idx + 1, now - list[idx]);
 
        return dp[idx][now];
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        list = new int[N];
        dp = new long[N][21];
 
        st = new StringTokenizer(br.readLine());
        for (int i = 0; i < N; i++) {
            list[i] = Integer.parseInt(st.nextToken());
        }
    }
 
    static void init() {
        for (int i = 0; i < N; i++) {
            Arrays.fill(dp[i], -1);
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        init();
        System.out.println(func(1, list[0]));
    }
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 5569 출근 경로  (0) 2021.02.06
boj 1010 다리 놓기  (0) 2021.02.05
boj 5573 산책  (0) 2021.02.04
boj 17528 Two Machines  (0) 2021.01.28
boj 9657 돌 게임 3  (0) 2021.01.27

www.acmicpc.net/problem/5573

 

5573번: 산책

첫째 줄에 H, W, N이 주어진다. (1 ≤ H,W ≤ 1000, 1 ≤ N ≤ 107) 둘째 줄부터 H개 줄에는 W개 정수가 주어진다. 이 정수는 상근이가 교차로에 써 놓은 문자의 정보이다. 0은 아래쪽을 의미하는 '아', 1은

www.acmicpc.net

1000 * 1000에 10000000번 산책을 하기때문에 시뮬레이션으로 접근하다가는 무조건 시간초과 뜹니다.

저는 방향정보를 dp를 이용하여 N - 1번까지 산책한 이후의 경로를 만들어 놓고 마지막 한 번 산책하는 방식으로 하였습니다.

 

dp에는 N - 1번의 산책동안 (x, y)에 몇 번 지나갔는지 표시하는데 사용하였습니다.

여기서 문제에서 산책하는 규칙이 있습니다.

0은 아래쪽, 1은 오른쪽 방향으로 가며 한 번 어떤 방향으로 가면 그 다음번 산책에서는 반드시 다른 방향으로 이동하게 되어있습니다.

따라서 dp[x][y]는 dp[x-1][y]에서 방문한 횟수의 1/2 + dp[x][y-1]에서 방문한 횟수의 1/2를 한 값입니다.

여기서 추가해야할 것이 dp[x-1][y], dp[x][y-1]이 홀수일 때 방향에 따라서도 방문횟수가 추가될 수 있습니다.

 

(x-1, y) 즉, 위쪽 방향에서 밑쪽으로 지나가려면 경로는 아래쪽 방향이 되어있어야합니다.

(x, y-1) 즉, 왼쪽 방향에서 오른쪽으로 지나가려면 경로는 오른쪽 방향이 되어있어야합니다.

위의 두가지를 추가하기 위해 처음에 받은 list[x-1][y], list[x][y-1]을 확인해야합니다.

 

(x-1, y)의 경우 처음 방향인 list[x-1][y]이 0이면 홀수일 때 1을 추가해줍니다.

(x, y-1)의 경우 처음 방향인 list[x][y-1]이 1이면 짝수일 때 1을 추가해줍니다.

 

이렇게 dp를 다 구하고 나면 이를 이용하여 산책경로를 모두 바꿔야합니다.

dp[x][y]가 짝수인 위치는 방향을 바꿀 필요 없고, 홀수인 위치에만 방향을 바꿔줍니다.

 

마지막으로 x=1, y=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
65
66
67
68
69
70
71
72
73
74
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static int list[][] = new int[1001][1001];
    static int H, W, N;
 
    static void solve() {
        int x = 1;
        int y = 1;
        while (true) {
            if (list[x][y] == 1)
                y++;
            else
                x++;
 
            if (x > H || y > W)
                break;
        }
 
        System.out.println(x + " " + y);
    }
 
    static void func() {
        int dp[][] = new int[H + 1][W + 1];
        for (int i = 1; i <= H; i++) {
            for (int j = 1; j <= W; j++) {
                if (i == 1 && j == 1) {
                    dp[i][j] = N - 1;
                    continue;
                }
                
                dp[i][j] = dp[i - 1][j] / 2 + dp[i][j - 1/ 2;
 
                if (dp[i - 1][j] % 2 == 1 && list[i - 1][j] == 0)
                    dp[i][j]++;
                if (dp[i][j - 1] % 2 == 1 && list[i][j - 1== 1)
                    dp[i][j]++;
            }
        }
 
        for (int i = 1; i <= H; i++) {
            for (int j = 1; j <= W; j++) {
                if (dp[i][j] % 2 == 0)
                    continue;
 
                list[i][j] = 1 - list[i][j];
            }
        }
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        H = Integer.parseInt(st.nextToken());
        W = Integer.parseInt(st.nextToken());
        N = Integer.parseInt(st.nextToken());
 
        for (int i = 1; i <= H; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 1; j <= W; j++) {
                list[i][j] = Integer.parseInt(st.nextToken());
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
        solve();
    }
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 1010 다리 놓기  (0) 2021.02.05
boj 5557 1학년  (0) 2021.02.05
boj 17528 Two Machines  (0) 2021.01.28
boj 9657 돌 게임 3  (0) 2021.01.27
boj 2096 내려가기  (0) 2021.01.22

www.acmicpc.net/problem/2243

 

2243번: 사탕상자

첫째 줄에 수정이가 사탕상자에 손을 댄 횟수 n(1≤n≤100,000)이 주어진다. 다음 n개의 줄에는 두 정수 A, B, 혹은 세 정수 A, B, C가 주어진다. A가 1인 경우는 사탕상자에서 사탕을 꺼내는 경우이다.

www.acmicpc.net

사탕의 맛이 1 ~ 1000000 까지 있습니다.

저는 맛을 인덱스로 하여 세그먼트 트리를 사용하여 구간 합을 구현하였습니다.

 

A가 1일 때, B는 꺼낼 사탕의 순위입니다.

A가 2일 때, B는 넣는 사탕의 맛이고, C는 갯수이며 양수면 넣는 경우, 음수면 빼는 경우입니다.

 

A = 2가 들어오면 B 인덱스에 C만큼 추가하면 되겠고

A = 1이 들어오면 사탕의 순위를 이분탐색으로 찾습니다.

 

이분탐색은 세그먼트 트리의 값을 이용하여 범위를 찾습니다.

x가 왼쪽 자식노드의 수보다 작거나 같으면 (tree[node * 2] >= x) l ~ m 범위로 내려가고 (더 낮은 구역을 탐색)

x가 왼쪽 자식노드의 수보다 크면 (tree[node * 2 < x) m + 1 ~ r의 범위로 내려갑니다. (더 높은 구역을 탐색)

이 때 m + 1 ~ r의 범위로 이동할 때 오른쪽 자식노드의 순위를 판단해야 하기때문에 x - tree[node * 2] 한 값을 보내줍니다.

 

마지막으로 l == r 구역에 도달하면 사탕을 한개 빼줘야하므로 update를 해주고 찾은 인덱스를 리턴해줍니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main {
    static final int MAX = 1000000;
    static int tree[] = new int[(MAX + 1* 4];
    static int N;
 
    static void update(int node, int s, int e, int idx, int diff) {
        if (idx < s || idx > e)
            return;
 
        if (s == e) {
            tree[node] += diff;
            return;
        }
 
        tree[node] += diff;
        int m = (s + e) / 2;
        update(node * 2, s, m, idx, diff);
        update(node * 2 + 1, m + 1, e, idx, diff);
    }
 
    static int binarysearch(int node, int l, int r, int x) {
        if (l == r) {
            update(11, MAX, l, -1);
            return l;
        }
 
        int m = (l + r) / 2;
        if (tree[node * 2>= x)
            return binarysearch(node * 2, l, m, x);
        else
            return binarysearch(node * 2 + 1, m + 1, r, x - tree[node * 2]);
    }
 
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        StringBuffer sb = new StringBuffer();
 
        N = Integer.parseInt(st.nextToken());
        while (N-- > 0) {
            st = new StringTokenizer(br.readLine());
            int type = Integer.parseInt(st.nextToken());
 
            if (type == 1) {
                int a = Integer.parseInt(st.nextToken());
                sb.append(binarysearch(11, MAX, a)).append("\n");
            } else {
                int a = Integer.parseInt(st.nextToken());
                int b = Integer.parseInt(st.nextToken());
 
                update(11, MAX, a, b);
            }
        }
 
        System.out.println(sb.toString());
    }
}
cs

'algorithm > SegmentTree' 카테고리의 다른 글

boj 14438 수열과 쿼리 17  (0) 2021.02.21
boj 13537 수열과 쿼리 1  (0) 2021.02.21
boj 6549 히스토그램에서 가장 큰 직사각형  (0) 2021.02.19
boj 2104 부분배열 고르기  (0) 2021.02.19
boj 2042 구간 합 구하기  (0) 2021.01.23

www.acmicpc.net/problem/2493

 

2493번: 탑

첫째 줄에 탑의 수를 나타내는 정수 N이 주어진다. N은 1 이상 500,000 이하이다. 둘째 줄에는 N개의 탑들의 높이가 직선상에 놓인 순서대로 하나의 빈칸을 사이에 두고 주어진다. 탑들의 높이는 1

www.acmicpc.net

탑 A의 왼쪽에 있는 탑들 중에서 탑 A보다 더 큰 높이의 탑들 중 가장 오른쪽의 탑의 위치를 구하는 문제입니다.

배열크기를 너무 높게잡으면 메모리초과까지 나올 수 있어서 초기에 배열크기를 잘 잡아야합니다.

N이 500000까지 들어오기때문에 N^2으로는 무조건 시간초과뜹니다

 

먼저 입력으로 주어지는 탑의 높이를 list에 저장하였고, 1번부터 N번까지 순회를 합니다.

 

스택에는 인덱스를 유지합니다.

i번 위치에서 스택이 비어있지 않고, list[top]이 list[i]보다 작을동안 pop을 해줍니다.

그 후에 스택이 비어있으면 0, 아니면 스택의 top을 출력하시면 됩니다.

 

 

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
package BOJ.data_structure;
 
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Stack;
import java.util.StringTokenizer;
 
public class Boj2493 {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static StringBuffer sb = new StringBuffer();
    static Stack<Integer> s = new Stack<>();
    static int list[];
    static int N;
 
    static void func() {
        for (int i = 0; i < N; i++) {
            while (!s.isEmpty() && list[s.peek()] < list[i])
                s.pop();
 
            if (s.isEmpty()) {
                s.push(i);
                sb.append("0 ");
            } else {
                sb.append(s.peek() + 1 + " ");
                s.push(i);
            }
        }
 
        System.out.println(sb.toString());
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        list = new int[N];
 
        st = new StringTokenizer(br.readLine());
        for (int i = 0; i < N; i++) {
            list[i] = Integer.parseInt(st.nextToken());
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

'algorithm > data-structure' 카테고리의 다른 글

boj 1918 후위 표기식  (0) 2021.02.05
boj 1935 후위 표기식2  (0) 2021.02.05
boj 6416 트리인가?  (0) 2021.02.04
boj 3190 뱀  (0) 2021.02.02
boj 2346 풍선 터뜨리기  (0) 2021.02.02

www.acmicpc.net/problem/1837

 

1837번: 암호제작

원룡이는 한 컴퓨터 보안 회사에서 일을 하고 있다. 그러던 도중, 원룡이는 YESWOA.COM 으로부터 홈페이지 유저들의 비밀키를 만들라는 지시를 받았다. 원룡이는 비밀 키를 다음과 같은 방법으로

www.acmicpc.net

BigInteger를 사용하는 문제입니다.

P는 소수의 곱으로 이루어져있지만 10^100이라는 수가 입력으로 주어집니다.

K는 P가 좋은 암호인지, 좋지 않은 암호인지 구별하는 수이며 1000000까지 주어집니다.

 

P를 나타내는 소수 p, q 중에 하나라도 K보다 작으면 이 암호P는 좋지 않은 암호입니다.

하지만 P가 너무 큰 수이기 때문에 소수를 직접 구할 수 없으므로 K범위 내의 소수를 모두 구하여

 

구한 소수들 중 P와 나머지 연산을 해서 0이 되는 수가 있으면 BAD, 없으면 GOOD를 출력하였습니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static BigInteger P, K;
    static boolean sosuchk[] = new boolean[1000001];
    static Set<BigInteger> sosu = new TreeSet<>();
    static int k;
 
    static void func() {
        Iterator<BigInteger> iter = sosu.iterator();
        while (iter.hasNext()) {
            BigInteger a = iter.next();
            if (a.compareTo(K) >= 0)
                break;
 
            if (P.mod(a).equals(new BigInteger("0"))) {
                System.out.println("BAD " + a);
                return;
            }
        }
 
        System.out.println("GOOD");
    }
 
    static void init() {
        for (int i = 2; i <= 1000000; i++) {
            if (sosuchk[i])
                continue;
 
            sosu.add(new BigInteger(Integer.toString(i)));
            for (int j = 2; i * j <= 1000000; j++) {
                if (sosuchk[i * j])
                    continue;
 
                sosuchk[i * j] = true;
            }
        }
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
 
        P = new BigInteger(st.nextToken());
        k = Integer.parseInt(st.nextToken());
        K = new BigInteger(Integer.toString(k));
    }
 
    public static void main(String[] args) throws Exception {
        init();
        input();
        func();
    }
}
cs

'algorithm > Math' 카테고리의 다른 글

boj 13136 Do Not Touch Anything  (0) 2022.10.25
boj 15740 A+B - 9  (0) 2021.01.31
boj 1002 터렛  (0) 2021.01.27

www.acmicpc.net/problem/6416

 

6416번: 트리인가?

트리는 굉장히 잘 알려진 자료 구조이다. 트리를 만족하는 자료 구조는 비어 있거나(노드의 개수가 0개), 노드의 개수가 1개 이상이고 방향 간선이 존재하며 다음과 같은 조건을 만족해야 한다.

www.acmicpc.net

자바라서 입력 받는거부터 좀 힘들었습니다..

다행히 검색으로 다음 토큰이 있는지 확인하는 st.hasMoreTokens() 라는 것을 찾아서 입력을 받았습니다.

 

이 문제는 u v 로 입력이 주어지고 이는 u->v를 뜻합니다.

트리이기 때문에 방향 그래프이고 한 방향으로만 향합니다. 즉, v->u는 안됩니다.

 

이 문제에서는 트리가 아닌 조건들을 모두 체크해주어야합니다.

1. 부모노드가 2개 이상인지

2. 루트노드가 1개가 아닌지 (0개이거나 2개 이상인지)

3. 사이클이 있는지

 

먼저 1번, 부모노드 확인입니다.

입력을 받으면서 자식으로 등록되는 노드(v)들을 Set을 이용하여 저장했고, 만약에 Set에 있는 값을 다시 넣게 된다면 자식으로 등록이 두번 됩니다. 즉 부모노드가 2개이상이 된다는 뜻입니다. => not tree

 

2번, 루트노드 확인입니다.

입력으로 주어지는 모든 부모노드(u)를 Set을 이용하여 저장했고, 만약에 Set에 있는 원소 중에 자식으로 등록되어있지 않으면 루트노드입니다.

만약 이러한 노드가 없거나 2개 이상이면 not tree입니다.

 

3번, 사이클 확인입니다.

map을 이용하여 Key는 부모노드(u), Value는 자식노드들(v)을 Integer, ArrayList<Integer>로 구현하였습니다.

사이클 확인은 dfs로 순회하여 next가 이미 방문한 노드인지 확인하였고, 이미 방문한 노드면 사이클이 있다는 말이기 때문에 not tree입니다.

 

3번의 확인이 끝나고 셋 다 아니라면 tree입니다.

 

 

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static StringBuffer sb = new StringBuffer();
    static Map<Integer, ArrayList<Integer>> m = new HashMap<>();
    static Set<Integer> findRoot = new HashSet<>();
    static Set<Integer> child = new HashSet<>();
    static Set<Integer> visit = new HashSet<>();
    static boolean tworoot, twoparents, cycle;
    static int u, v, root;
 
    static void dfs(int x) {
        visit.add(x);
 
        ArrayList<Integer> graph = m.get(x);
        if (graph == null)
            return;
 
        for (int i = 0; i < graph.size(); i++) {
            int next = graph.get(i);
 
            if (visit.contains(next)) {
                cycle = true;
                return;
            }
 
            dfs(next);
            if (cycle)
                return;
        }
    }
 
    static void rootFinding() {
        Iterator<Integer> iter = findRoot.iterator();
        while (iter.hasNext()) {
            int x = iter.next();
 
            if (!child.contains(x)) {
                if (root != 0) {
                    tworoot = true;
                    return;
                }
                root = x;
            }
        }
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        while (true) {
            while (!st.hasMoreTokens())
                st = new StringTokenizer(br.readLine());
 
            u = Integer.parseInt(st.nextToken());
            v = Integer.parseInt(st.nextToken());
            if (u == 0 || u == -1)
                return;
 
            if (m.containsKey(u)) {
                m.get(u).add(v);
            } else {
                ArrayList<Integer> tmp = new ArrayList<>();
                tmp.add(v);
                m.put(u, tmp);
            }
            if (child.contains(v))
                twoparents = true;
            else
                child.add(v);
 
            findRoot.add(u);
        }
    }
 
    static void clear() {
        m.clear();
        findRoot.clear();
        child.clear();
        visit.clear();
        twoparents = false;
        tworoot = false;
        cycle = false;
        root = 0;
    }
 
    public static void main(String[] args) throws Exception {
        for (int T = 1;; T++) {
            input();
            if (u == -1)
                break;
 
            sb.append("Case " + T + " is ");
            if (child.isEmpty()) {
                sb.append("a tree.\n");
                continue;
            }
            if (twoparents) {
                sb.append("not a tree.\n");
                clear();
                continue;
            }
 
            rootFinding();
            if (root == 0 || tworoot) {
                sb.append("not a tree.\n");
                clear();
                continue;
            }
 
            dfs(root);
            if (cycle)
                sb.append("not a tree.\n");
            else
                sb.append("a tree.\n");
 
            clear();
        }
 
        System.out.println(sb.toString());
    }
}
cs

'algorithm > data-structure' 카테고리의 다른 글

boj 1935 후위 표기식2  (0) 2021.02.05
boj 2493 탑  (0) 2021.02.04
boj 3190 뱀  (0) 2021.02.02
boj 2346 풍선 터뜨리기  (0) 2021.02.02
boj 5397 키로거  (0) 2021.02.02

+ Recent posts