www.acmicpc.net/problem/11049

 

11049번: 행렬 곱셈 순서

첫째 줄에 입력으로 주어진 행렬을 곱하는데 필요한 곱셈 연산의 최솟값을 출력한다. 정답은 231-1 보다 작거나 같은 자연수이다. 또한, 최악의 순서로 연산해도 연산 횟수가 231-1보다 작거나 같

www.acmicpc.net

N * M 행렬과 M * K 행렬을 곱할때는 N * M * K번의 연산이 필요합니다.

이 공식을 이용해서 여러개의 행렬을 곱하는데 필요한 곱셈 연산의 수를 최소로 해야합니다.

입력으로는 순서대로 곱셈이 가능하게 주어지므로 순서대로 연산을 할 수 있습니다.

 

저는 3중for문을 사용하였습니다.

i는 간격, x는 시작 인덱스, y는 중간 인덱스, k는 끝 인덱스를 나타내었습니다.

dp[x][k]는 dp[x][y] + dp[y + 1][k]

즉, (x ~ y번째 행렬을 곱할 때 연산의 최솟값) + (y + 1 ~ k번째 행렬을 곱할 때 연산의 최솟값) 에다가

x ~ y번째가 합쳐있는 행렬과 y + 1 ~ k번째가 합쳐있는 행렬을 곱할 때 필요한 연산을 더해주어야합니다.

 

그러면 점화식은 dp[x][k] = min(dp[x][k], dp[x][y] + dp[y + 1][k] + list[x].first * list[y].second * list[k].secod) 가 될 수 있습니다.

출력은 dp[1][N] (1 ~ 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
#include <iostream>
#include <algorithm>
using namespace std;
 
pair<intint> list[501];
int dp[501][501];
int N;
 
void func() {
    for (int i = 1; i < N; i++) {
        for (int x = 1; x + i <= N; x++) {
            int k = x + i;
            for (int y = x; y < k; y++) {
                if (!dp[x][y])
                    dp[x][k] = dp[x][y] + dp[y + 1][k] + list[x].first * list[y].second * list[k].second;
                else
                    dp[x][k] = min(dp[x][k], dp[x][y] + dp[y + 1][k] + list[x].first * list[y].second * list[k].second);
            }
        }
    }
 
    cout << dp[1][N] << '\n';
}
 
void input() {
    cin >> N;
    for (int i = 1; i <= N; i++) {
        cin >> list[i].first >> list[i].second;
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
    
    input();
    func();
 
    return 0;
}
cs

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

boj 17404 RGB거리 2  (0) 2021.02.28
boj 2616 소형기관차  (0) 2021.02.27
boj 1915 가장 큰 정사각형  (0) 2021.02.20
boj 1912 연속합  (0) 2021.02.18
boj 10211 Maximum Subarray  (0) 2021.02.18

www.acmicpc.net/problem/1915

 

1915번: 가장 큰 정사각형

첫째 줄에 n, m(1 ≤ n, m ≤ 1,000)이 주어진다. 다음 n개의 줄에는 m개의 숫자로 배열이 주어진다.

www.acmicpc.net

이런식으로 배열이 주어지면 1로만 이루어진 가장 큰 정사각형의 넓이를 구하는 문제입니다.

 

우선 2 * 2의 정사각형의 예로 들면

여기서 맨 오른쪽 아래(2, 2)를 기준으로 왼쪽(2, 1), 위(1, 2), 왼쪽 위(1, 1)의 수가 모두 1이기때문에 정사각형이 됩니다.

여기서 dp[i][j]의 값은 dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]의 값들로 인해 결정이 되는것을 알 수 있습니다.

 

 

위의 그림은 dp[i - 1][j - 1]이 0이므로 정사각형이 아닙니다.

 

여기서 도출되는 점화식은 dp[i][j] += min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1])입니다.

이 점화식은 현재 좌표의 값이 1일 경우에만 적용됩니다. (0일 경우에는 그냥 넘겨줍니다)

계산 과정에서 ans를 계속 갱신시켜줘서 마지막에 넓이를 출력해주시면 됩니다.

 

 

[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
#include <iostream>
#include <algorithm>
using namespace std;
 
int dp[1001][1001];
int N, M, ans;
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    char ch;
    cin >> N >> M;
 
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            cin >> ch;
            dp[i][j] = ch - '0';
            if (dp[i][j]) dp[i][j] += min(dp[i - 1][j], min(dp[i][j - 1], dp[i - 1][j - 1]));
            ans = max(ans, dp[i][j]);
        }
    }
 
    cout << ans * ans << '\n';
 
    return 0;
}
cs

 

 

[Java]

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
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 dp[][] = new int[1001][1001];
    static int N, M, ans;
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
 
        for (int i = 1; i <= N; i++) {
            st = new StringTokenizer(br.readLine());
            char ch[] = st.nextToken().toCharArray();
            for (int j = 1; j <= M; j++) {
                dp[i][j] = ch[j - 1- '0';
 
                if (dp[i][j] == 1) {
                    dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i][j - 1], dp[i - 1][j])) + 1;
                    ans = Math.max(ans, dp[i][j]);
                }
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        System.out.println(ans * ans);
    }
}
cs

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

boj 2616 소형기관차  (0) 2021.02.27
boj 11049 행렬 곱셈 순서  (0) 2021.02.20
boj 1912 연속합  (0) 2021.02.18
boj 10211 Maximum Subarray  (0) 2021.02.18
boj 10826 피보나치 수 4  (0) 2021.02.08

 

www.acmicpc.net/problem/1525

 

1525번: 퍼즐

세 줄에 걸쳐서 표에 채워져 있는 아홉 개의 수가 주어진다. 한 줄에 세 개의 수가 주어지며, 빈 칸은 0으로 나타낸다.

www.acmicpc.net

3 * 3 퍼즐을 이동시켜서 위와같은 상태로 만들고, 이동의 최소 횟수를 출력하고, 불가능한 경우 -1를 출력합니다.

 

저는 3 * 3 퍼즐을 String으로 변환시켰습니다.

1 0 3
4 2 5
7 8 6

입력이 이렇게 주어지면 "103425786"을 만든 다음 bfs를 돌렸습니다. (방문체크도 Set<String>으로 하였습니다.)

그리고 각 칸에서 움직일 수 있는 공간을 ArrayList배열을 만들어서 모두 만들어줍니다.

왼쪽 위 칸 번호가 0번부터 시작해서 오른쪽 아래 칸 번호가 8번이되어 

0 -> 1, 3

1 -> 0, 2, 4

2 -> 1, 5

3 -> 0, 4, 6

4 -> 1, 3, 5, 7

5 -> 2, 4, 8

6 -> 3, 7

7 -> 4, 6, 8

8 -> 5, 7

이렇게 그래프를 연결시킬 수 있습니다.

 

이제 bfs를 돌려줍니다.

덱에 입력받은 문자열(str), 0의 위치(idx), 움직인 횟수(cnt)를 넣어줍니다.

bfs 과정에서는 현재 문자열에서 idx위치와 next위치의 문자열을 서로 바꿔줍니다.

그리고 중복체크를 하고, 덱에 넣어주는 방식으로 하였습니다.

 

덱에서 꺼낸 문자열이 ans인 "123456780"과 같으면 cnt를 출력하고 리턴합니다.

만약 ans와 같은 문자열이 나오지 않았는데 덱이 비어있게되면 "123456780"을 만들수 없으므로 -1을 출력합니다.

 

 

[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
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
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <set>
using namespace std;
 
typedef struct list {
    string now;
    int idx;
    int cnt;
}list;
 
queue<list> q;
set<string> s;
vector<int> v[9];
string ans = "123456780", str = "";
 
void init() {
    v[0].push_back(1);
    v[0].push_back(3);
 
    v[1].push_back(0);
    v[1].push_back(2);
    v[1].push_back(4);
 
    v[2].push_back(1);
    v[2].push_back(5);
 
    v[3].push_back(0);
    v[3].push_back(4);
    v[3].push_back(6);
 
    v[4].push_back(1);
    v[4].push_back(3);
    v[4].push_back(5);
    v[4].push_back(7);
 
    v[5].push_back(2);
    v[5].push_back(4);
    v[5].push_back(8);
 
    v[6].push_back(3);
    v[6].push_back(7);
 
    v[7].push_back(4);
    v[7].push_back(6);
    v[7].push_back(8);
 
    v[8].push_back(5);
    v[8].push_back(7);
}
 
void bfs() {
    while (!q.empty()) {
        string now = q.front().now;
        int idx = q.front().idx;
        int cnt = q.front().cnt;
        q.pop();
 
        if (!now.compare(ans)) {
            cout << cnt << '\n';
            return;
        }
 
        for (int i = 0; i < v[idx].size(); i++) {
            int next = v[idx][i];
            string tmp = now;
            swap(tmp[idx], tmp[next]);
 
            if (s.find(tmp) != s.end()) continue;
 
            q.push({ tmp, next, cnt + 1 });
            s.insert(tmp);
        }
    }
 
    cout << "-1\n";
}
 
void input() {
    int k = 0;
    string tmp = "";
    for (int i = 0; i < 9; i++) {
        cin >> tmp;
        str += tmp;
 
        if (tmp[0== '0') {
            k = i;
        }
    }
 
    q.push({ str, k, 0 });
    s.insert(str);
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    init();
    input();
    bfs();
 
    return 0;
}
cs

 

 

[Java]

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
 
public class Main {
    static class Pair {
        String now;
        int idx;
        int cnt;
 
        public Pair(String now, int idx, int cnt) {
            this.now = now;
            this.idx = idx;
            this.cnt = cnt;
        }
    }
 
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static String ans = "123456780";
    static ArrayList<Integer> list[] = new ArrayList[9];
    static String str = "";
 
    static void init() {
        for (int i = 0; i < 9; i++)
            list[i] = new ArrayList<>();
 
        list[0].add(1);
        list[0].add(3);
 
        list[1].add(0);
        list[1].add(2);
        list[1].add(4);
 
        list[2].add(1);
        list[2].add(5);
 
        list[3].add(0);
        list[3].add(4);
        list[3].add(6);
 
        list[4].add(1);
        list[4].add(3);
        list[4].add(5);
        list[4].add(7);
 
        list[5].add(2);
        list[5].add(4);
        list[5].add(8);
 
        list[6].add(3);
        list[6].add(7);
 
        list[7].add(4);
        list[7].add(6);
        list[7].add(8);
 
        list[8].add(5);
        list[8].add(7);
    }
 
    static void bfs() {
        Set<String> s = new HashSet<>();
        Deque<Pair> dq = new ArrayDeque<>();
        dq.add(new Pair(str, str.indexOf("0"), 0));
        s.add(new String(str));
        while (!dq.isEmpty()) {
            String now = dq.peek().now;
            int idx = dq.peek().idx;
            int cnt = dq.poll().cnt;
 
            if (now.equals(ans)) {
                System.out.println(cnt);
                return;
            }
 
            for (int i = 0; i < list[idx].size(); i++) {
                int next = list[idx].get(i);
                char newstr[] = new String(now).toCharArray();
                char tmp = newstr[idx];
                newstr[idx] = newstr[next];
                newstr[next] = tmp;
 
                String s1 = String.valueOf(newstr);
                if (s.contains(s1))
                    continue;
 
                dq.add(new Pair(s1, next, cnt + 1));
                s.add(new String(s1));
            }
        }
 
        System.out.println(-1);
    }
 
    static void input() throws Exception {
        for (int i = 0; i < 3; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < 3; j++) {
                str += st.nextToken();
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        init();
        input();
        bfs();
    }
}
cs

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

boj 11559 Puyo Puyo  (0) 2021.02.26
boj 15653 구슬 탈출 4  (0) 2021.02.22
boj 7576 토마토  (0) 2021.02.19
boj 17135 캐슬 디펜스  (0) 2021.02.17
boj 16236 아기 상어  (0) 2021.02.14

www.acmicpc.net/problem/7576

 

7576번: 토마토

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M,N ≤ 1,000 이다. 둘째 줄부터는 하나의 상자에 저장된 토마토

www.acmicpc.net

bfs를 이용하여 익은 토마토와 근접해있는 토마토를 익게해서 모든 토마토를 익혀야합니다.

하지만 토마토가 들어있지 않은 칸이 있기때문에 모든 토마토가 익지 않을 수도 있습니다.

그리고 입력으로 이미 모든 토마토가 익어있으면 0을 출력해야합니다.

 

우선 입력을 받고, 0의 갯수(ans)를 모두 세어 유지합니다.

그리고 1을 입력받으면 덱에 넣고 방문처리도 해줍니다. (bfs 사용)

그 다음 bfs를 돌리기 전에 이미 ans가 0이면 0을 출력하고 리턴합니다.

 

확인이 끝나면 bfs를 돌려줍니다.

하루에 한칸씩 번지기때문에 덱에 있던 좌표들만 돌려야합니다. (t로 날짜 계산)

for문을 덱이 비어있지 않을동안 돌려주고 현재 덱의 크기를 size에 넣어서 size 만큼만 bfs를 돌려줍니다. (1일치)

 

이후에 ans가 0이 되면 모두 익었다는 뜻이므로 t를 출력합니다.

ans가 0이 되지 않았는데 덱이 비어버리면 모두 익지 않았다는 뜻이므로 -1을 출력합니다.

 

 

[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
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
#include <iostream>
#include <queue>
using namespace std;
 
queue<pair<intint> > q;
int direct[4][2= { {0,1},{1,0},{0,-1},{-1,0} };
bool visit[1001][1001];
int list[1001][1001];
int N, M, ans;
 
void bfs() {
    int t = 1;
    for (; !q.empty(); t++) {
        int qsize = q.size();
        while (qsize--) {
            int x = q.front().first;
            int y = q.front().second;
            q.pop();
 
            for (int i = 0; i < 4; i++) {
                int nx = x + direct[i][0];
                int ny = y + direct[i][1];
                
                if (nx < 0 || ny < 0 || nx >= N || ny >= M) continue;
                if (visit[nx][ny] || list[nx][ny] == -1continue;
 
                q.push({ nx,ny });
                visit[nx][ny] = true;
                ans--;
            }
        }
 
        if (!ans) {
            cout << t << '\n';
            return;
        }
    }
 
    cout << "-1\n";
}
 
void func() {
    if (!ans) {
        cout << "0\n";
        return;
    }
 
    bfs();
}
 
void input() {
    cin >> M >> N;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> list[i][j];
            if (!list[i][j])
                ans++;
            else if (list[i][j] == 1) {
                q.push({ i,j });
                visit[i][j] = true;
            }
        }
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

 

 

[Java]

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static Deque<int[]> dq = new ArrayDeque<>();
    static int direct[][] = { { 01 }, { 10 }, { 0-1 }, { -10 } };
    static boolean visit[][];
    static int list[][];
    static int N, M, ans;
 
    static void bfs() {
        int t = 1;
        for (; !dq.isEmpty(); t++) {
            int size = dq.size();
 
            while (size-- > 0) {
                int x = dq.peekFirst()[0];
                int y = dq.pollFirst()[1];
 
                for (int i = 0; i < 4; i++) {
                    int nx = x + direct[i][0];
                    int ny = y + direct[i][1];
 
                    if (nx < 0 || ny < 0 || nx >= N || ny >= M)
                        continue;
                    if (list[nx][ny] == -1 || visit[nx][ny])
                        continue;
 
                    visit[nx][ny] = true;
                    dq.addLast(new int[] { nx, ny });
                    ans--;
                }
            }
 
            if (ans == 0)
                break;
        }
        if (ans == 0)
            System.out.println(t);
        else
            System.out.println(-1);
    }
 
    static void func() {
        if (ans == 0) {
            System.out.println(0);
            return;
        }
 
        bfs();
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        M = Integer.parseInt(st.nextToken());
        N = Integer.parseInt(st.nextToken());
        list = new int[N][M];
        visit = new boolean[N][M];
 
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < M; j++) {
                list[i][j] = Integer.parseInt(st.nextToken());
                if (list[i][j] == 0)
                    ans++;
                else if (list[i][j] == 1) {
                    dq.addLast(new int[] { i, j });
                    visit[i][j] = true;
                }
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

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

boj 15653 구슬 탈출 4  (0) 2021.02.22
boj 1525 퍼즐  (0) 2021.02.19
boj 17135 캐슬 디펜스  (0) 2021.02.17
boj 16236 아기 상어  (0) 2021.02.14
boj 10026 적록색약  (0) 2021.02.13

www.acmicpc.net/problem/6549

 

6549번: 히스토그램에서 가장 큰 직사각형

입력은 테스트 케이스 여러 개로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있고, 직사각형의 수 n이 가장 처음으로 주어진다. (1 ≤ n ≤ 100,000) 그 다음 n개의 정수 h1, ..., hn (0 ≤ hi ≤

www.acmicpc.net

emoney96.tistory.com/138

 

boj 2104 부분배열 고르기

www.acmicpc.net/problem/2104 2104번: 부분배열 고르기 크기가 N(1≤N≤100,000)인 1차원 배열 A[1], …, A[N]이 있다. 어떤 i, j(1≤i≤j≤N)에 대한 점수는, (A[i]+…+A[j])×Min{A[i], …, A[j]}가 된다. 즉,..

emoney96.tistory.com

이 문제와 같은 풀이방법입니다.

세그먼트 트리로 구간의 최솟값만 트리에 저장하였습니다.

 

구간 [l, r]의 최솟값의 인덱스를 query함수로 찾아내고 list[idx]에 구간의 길이를 곱한 값이 직사각형의 넓이입니다.

idx를 기준으로 왼쪽(l, idx - 1) 구간, 오른쪽(idx + 1, r) 구간의 넓이와 [l, r]에서 구했던 넓이의 최댓값을 출력하면 됩니다.

 

 

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
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 tree[] = new int[400004];
    static long list[] = new long[100001];
    static int N;
 
    static int init(int node, int s, int e) {
        if (s == e)
            return tree[node] = s;
 
        int m = (s + e) / 2;
        int l = init(node * 2, s, m);
        int r = init(node * 2 + 1, m + 1, e);
        return tree[node] = list[l] < list[r] ? l : r;
    }
 
    static int query(int node, int s, int e, int l, int r) {
        if (l > e || s > r)
            return -1;
        if (l <= s && e <= r)
            return tree[node];
 
        int m = (s + e) / 2;
        int a = query(node * 2, s, m, l, r);
        int b = query(node * 2 + 1, m + 1, e, l, r);
 
        if (a == -1)
            return b;
        else if (b == -1)
            return a;
        else
            return list[a] < list[b] ? a : b;
    }
 
    static long func(int l, int r) {
        int idx = query(11, N, l, r);
        long sum = list[idx] * (r - l + 1);
 
        if (idx > l)
            sum = Math.max(sum, func(l, idx - 1));
        if (idx < r)
            sum = Math.max(sum, func(idx + 1, r));
 
        return sum;
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        if (N == 0)
            return;
 
        for (int i = 1; i <= N; i++) {
            list[i] = Integer.parseInt(st.nextToken());
        }
        init(11, N);
    }
 
    public static void main(String[] args) throws Exception {
        while (true) {
            input();
            if (N == 0)
                break;
            sb.append(func(1, N)).append("\n");
        }
        
        System.out.println(sb.toString());
    }
}
cs

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

boj 14438 수열과 쿼리 17  (0) 2021.02.21
boj 13537 수열과 쿼리 1  (0) 2021.02.21
boj 2104 부분배열 고르기  (0) 2021.02.19
boj 2243 사탕상자  (0) 2021.02.04
boj 2042 구간 합 구하기  (0) 2021.01.23

www.acmicpc.net/problem/2104

 

2104번: 부분배열 고르기

크기가 N(1≤N≤100,000)인 1차원 배열 A[1], …, A[N]이 있다. 어떤 i, j(1≤i≤j≤N)에 대한 점수는, (A[i]+…+A[j])×Min{A[i], …, A[j]}가 된다. 즉, i부터 j까지의 합에다가 i부터 j까지의 최솟값을 곱한 것이

www.acmicpc.net

www.acmicpc.net/problem/6549

 

6549번: 히스토그램에서 가장 큰 직사각형

입력은 테스트 케이스 여러 개로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있고, 직사각형의 수 n이 가장 처음으로 주어진다. (1 ≤ n ≤ 100,000) 그 다음 n개의 정수 h1, ..., hn (0 ≤ hi ≤

www.acmicpc.net

이문제와 같은 방법으로 해결하였습니다.

 

우선 세그먼트 트리로 구간 합과 최솟값을 모두 tree배열에 저장하였습니다.

그 다음 func함수에서 [s, e]구간의 최솟값의 인덱스(idx)과 구간 합(query)을 찾아내어 곱한 값을 sum에 저장하고,

idx를 기준으로 왼쪽(s, idx - 1), 오른쪽(idx + 1, e) 구간으로 나누어 각각의 sum의 최댓값을 찾은 후에 출력하였습니다.

이 방법말고 다른방법으로 해결하는 방법이 있던데 알려주신 분의 코드를 뜯어봐야 할 것 같습니다...

 

 

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
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 long tree[][] = new long[400004][2];
    static int list[] = new int[100001];
    static int N;
 
    static long[] init(int node, int s, int e) {
        if (s == e) {
            tree[node][0= list[s];
            tree[node][1= s;
            return tree[node];
        }
 
        int m = (s + e) / 2;
        long l[] = init(node * 2, s, m);
        long r[] = init(node * 2 + 1, m + 1, e);
        tree[node][0= l[0+ r[0];
        if (list[(int) l[1]] < list[(int) r[1]])
            tree[node][1= l[1];
        else
            tree[node][1= r[1];
        return tree[node];
    }
 
    static long query(int node, int s, int e, int l, int r) {
        if (s > r || l > e)
            return 0;
        if (l <= s && e <= r)
            return tree[node][0];
 
        int m = (s + e) / 2;
        return query(node * 2, s, m, l, r) + query(node * 2 + 1, m + 1, e, l, r);
    }
 
    static long findmin(int node, int s, int e, int l, int r) {
        if (s > r || l > e)
            return -1;
        if (l <= s && e <= r)
            return tree[node][1];
 
        int m = (s + e) / 2;
        long a = findmin(node * 2, s, m, l, r);
        long b = findmin(node * 2 + 1, m + 1, e, l, r);
        if (a == -1)
            return b;
        else if (b == -1)
            return a;
        else {
            if (list[(int) a] > list[(int) b])
                return b;
            else
                return a;
        }
    }
 
    static long func(int s, int e) {
        int idx = (int) findmin(11, N, s, e);
        long sum = query(11, N, s, e) * list[idx];
 
        if (s < idx)
            sum = Math.max(sum, func(s, idx - 1));
        if (idx < e)
            sum = Math.max(sum, func(idx + 1, e));
 
        return sum;
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        st = new StringTokenizer(br.readLine());
        for (int i = 1; i <= N; i++) {
            list[i] = Integer.parseInt(st.nextToken());
        }
 
        init(11, N);
    }
 
    public static void main(String[] args) throws Exception {
        input();
        System.out.println(func(1, N));
    }
}
cs

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

boj 14438 수열과 쿼리 17  (0) 2021.02.21
boj 13537 수열과 쿼리 1  (0) 2021.02.21
boj 6549 히스토그램에서 가장 큰 직사각형  (0) 2021.02.19
boj 2243 사탕상자  (0) 2021.02.04
boj 2042 구간 합 구하기  (0) 2021.01.23

www.acmicpc.net/problem/1912

 

1912번: 연속합

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

www.acmicpc.net

배열이 주어지면 연속된 수를 선택하여 얻을 수 있는 합을 최대로 해야합니다.

dp를 이용하여 간단하게 해결하였지만 분할정복 기법으로 사용한 소스도 같이 올리겠습니다.

 

우선 dp는 간단합니다.

(i번째 수)와 (i - 1까지의 연속합 최대에 i번째 수를 더한 값) 중 최댓값이 dp[i]가 됩니다.

입력이 음수로 들어오기때문에 ans를 미리 Integer.MIN_VALUE로 최솟값을 만들어 놓고 진행합니다.

합의 최대가 N번째에 온다는 보장이 없기때문에 dp를 구할때마다 갱신해줍니다.

 

 

[dp]

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
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 dp[];
    static int N, ans = Integer.MIN_VALUE;
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        dp = new int[N + 1];
        st = new StringTokenizer(br.readLine());
        for (int i = 1; i <= N; i++) {
            dp[i] = Integer.parseInt(st.nextToken());
            dp[i] = Math.max(dp[i], dp[i - 1+ dp[i]);
            ans = Math.max(ans, dp[i]);
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        System.out.println(ans);
    }
}
 
cs

 

다음은 분할정복 기법입니다. 시간상으로는 dp가 더 빠르지만 오늘 배운내용으로 한번 해보았습니다.

구간 1 ~ N 에서의 최대 연속합을 구합니다.

1. 왼쪽(l ~ m) 구간

2. 오른쪽(m + 1 ~ r)

3. 1과 2 모두 포함하는 부분배열의 합을 모두 구해주시면 됩니다.

 

1, 2번은 이분탐색 방식으로 나눠주시면 되고,

3번을 구할때는 m은 무조건 포함하기 때문에 m부터 왼쪽(l까지)으로 인덱스를 옮겨가며 sum에 더해줍니다.

이 때, 더하면서 leftmax를 계속 갱신시켜줍니다.

그리고 m + 1부터 오른쪽(r까지)으로 인덱스를 옮겨가며 sum에 더해줍니다.

이 때도 마찬가지로 더하면서 rightmax를 계속 갱신시켜줍니다.

 

이 문제의 답은 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
43
44
45
46
47
48
49
50
51
52
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[];
    static int N, ans = Integer.MIN_VALUE;
 
    static int binarysearch(int l, int r) {
        if (l == r)
            return list[l];
 
        int m = (l + r) / 2;
        int leftmax = Integer.MIN_VALUE;
        int rightmax = Integer.MIN_VALUE;
        int sum = 0;
        for (int i = m; i >= l; i--) {
            sum += list[i];
            leftmax = Math.max(leftmax, sum);
        }
 
        sum = 0;
        for (int i = m + 1; i <= r; i++) {
            sum += list[i];
            rightmax = Math.max(rightmax, sum);
        }
 
        return Math.max(leftmax + rightmax, Math.max(binarysearch(l, m), binarysearch(m + 1, r)));
    }
 
    static void func() {
        System.out.println(binarysearch(1, N));
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        list = new int[N + 1];
 
        st = new StringTokenizer(br.readLine());
        for (int i = 1; i <= N; i++) {
            list[i] = Integer.parseInt(st.nextToken());
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

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

boj 11049 행렬 곱셈 순서  (0) 2021.02.20
boj 1915 가장 큰 정사각형  (0) 2021.02.20
boj 10211 Maximum Subarray  (0) 2021.02.18
boj 10826 피보나치 수 4  (0) 2021.02.08
boj 5569 출근 경로  (0) 2021.02.06

www.acmicpc.net/problem/10211

 

10211번: Maximum Subarray

크기 N인 정수형 배열 X가 있을 때, X의 부분 배열(X의 연속한 일부분) 중 각 원소의 합이 가장 큰 부분 배열을 찾는 Maximum subarray problem(최대 부분배열 문제)은 컴퓨터 과학에서 매우 잘 알려져 있

www.acmicpc.net

www.acmicpc.net/problem/1912

 

1912번: 연속합

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

www.acmicpc.net

위의 문제와 같은문제이지만 N의 범위가 적게 들어옵니다.

저는 dp와 세그먼트 트리 두가지 방법으로 해결하였습니다.

이 문제는 당연히 dp로 해결한 것이 속도가 빠르기 때문에 dp로 접근하시면 됩니다.

세그먼트 트리는 그냥 해본거에요..

근데 이문제는 그냥 브루트포스로 모든경우를 다구해도 풀립니다.. 밑에 소스첨부합니다

 

dp의 점화식은 이전 인덱스까지 더한 dp값에 현재 자신의 값을 더한것과 자신의 값 중 큰 값이되어

dp[i] = max(dp[i - 1] + list[i], list[i]) 가 되겠습니다.

 

 

[dp]

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
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 list[], dp[];
    static int N;
 
    static void func() {
        int ans = Integer.MIN_VALUE;
        for (int i = 1; i <= N; i++) {
            dp[i] = Math.max(dp[i - 1+ list[i], list[i]);
            ans = Math.max(ans, dp[i]);
        }
        
        sb.append(ans).append("\n");
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        list = new int[N + 1];
        dp = new int[N + 1];
 
        st = new StringTokenizer(br.readLine());
        for (int i = 1; i <= N; i++) {
            list[i] = Integer.parseInt(st.nextToken());
        }
    }
 
    public static void main(String[] args) throws Exception {
        st = new StringTokenizer(br.readLine());
        int tc = Integer.parseInt(st.nextToken());
        while (tc-- > 0) {
            input();
            func();
        }
        
        System.out.println(sb.toString());
    }
}
cs

 

세그먼트 트리 방법으로는 입력으로 list를 받으면

init함수로 각 구간의 합을 미리 구해놓습니다.

이중 for문으로 (i, i ~ 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
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 tree[] = new int[4004];
    static int list[] = new int[1001];
    static int N;
 
    static int init(int node, int s, int e) {
        if (s == e)
            return tree[node] = list[s];
 
        int m = (s + e) / 2;
        return tree[node] = init(node * 2, s, m) + init(node * 2 + 1, m + 1, e);
    }
 
    static int query(int node, int s, int e, int l, int r) {
        if (s > r || l > e)
            return 0;
        if (l <= s && e <= r)
            return tree[node];
 
        int m = (s + e) / 2;
        return query(node * 2, s, m, l, r) + query(node * 2 + 1, m + 1, e, l, r);
    }
 
    static void func() {
        int ans = Integer.MIN_VALUE;
        for (int i = 1; i <= N; i++) {
            for (int j = i; j <= N; j++) {
                ans = Math.max(ans, query(11, N, i, j));
            }
        }
        
        sb.append(ans).append("\n");
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        st = new StringTokenizer(br.readLine());
        for (int i = 1; i <= N; i++) {
            list[i] = Integer.parseInt(st.nextToken());
        }
        init(11, N);
    }
 
    public static void main(String[] args) throws Exception {
        st = new StringTokenizer(br.readLine());
        int tc = Integer.parseInt(st.nextToken());
        while (tc-- > 0) {
            input();
            func();
        }
        
        System.out.println(sb.toString());
    }
}
cs

 

[브루트포스]

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
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 list[];
    static int N;
 
    static void func() {
        int ans = Integer.MIN_VALUE;
        for (int i = 0; i < N; i++) {
            for (int j = i; j < N; j++) {
                int sum = 0;
                for (int k = i; k <= j; k++) {
                    sum += list[k];
                }
                ans = Math.max(ans, sum);
            }
        }
        sb.append(ans).append("\n");
    }
 
    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 {
        st = new StringTokenizer(br.readLine());
        int tc = Integer.parseInt(st.nextToken());
        while (tc-- > 0) {
            input();
            func();
        }
 
        System.out.println(sb.toString());
    }
}
cs

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

boj 1915 가장 큰 정사각형  (0) 2021.02.20
boj 1912 연속합  (0) 2021.02.18
boj 10826 피보나치 수 4  (0) 2021.02.08
boj 5569 출근 경로  (0) 2021.02.06
boj 1010 다리 놓기  (0) 2021.02.05

www.acmicpc.net/problem/1987

 

1987번: 알파벳

세로 R칸, 가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸 (1행 1열) 에는 말이 놓여 있다. 말은 상하좌우로 인접한 네 칸 중의 한 칸으

www.acmicpc.net

 

문제에서 요구하는 조건은

1. 말은 (0, 0)에서 출발합니다.

2. 말은 상하좌우 방향으로 움직일 수 있습니다.

3. 말이 지나가는 동안 밟은 칸의 알파벳은 모두 달라야합니다.

 

말이 (0, 0)에서 출발하여 지나갈 수 있는 최대의 칸 수를 출력해야합니다.

저는 백트래킹으로 해결하였고 해당 칸을 방문체크하는 visit배열과 칸에 있는 알파벳 중복체크를 위한 alphachk 배열을 사용하였습니다.

 

재귀를 돌릴때마다 답을 갱신해주고, 해당 칸과 알파벳에 방문처리합니다.

그 다음 4방향 탐색하여 맵 밖으로 나갔는지, 이미 방문하였거나 밟은 적이 있는 알파벳인지 체크를 해줍니다.

모두 통과하면 nx, ny, cnt+1를 재귀로 넘겨주고, 빠져나오면 true했던 boolean배열을 모두 false로 바꿔줍니다.

마지막으로 정답을 출력합니다.

 

 

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
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 direct[][] = { { 01 }, { 10 }, { 0-1 }, { -10 } };
    static boolean visit[][], alphachk[];
    static char list[][];
    static int N, M, ans;
 
    static void dfs(int x, int y, int cnt) {
        ans = Math.max(ans, cnt);
        visit[x][y] = true;
        alphachk[list[x][y] - 'A'= true;
 
        for (int i = 0; i < 4; i++) {
            int nx = x + direct[i][0];
            int ny = y + direct[i][1];
 
            if (nx < 0 || ny < 0 || nx >= N || ny >= M)
                continue;
            if (visit[nx][ny] || alphachk[list[nx][ny] - 'A'])
                continue;
 
            dfs(nx, ny, cnt + 1);
            alphachk[list[nx][ny] - 'A'= false;
            visit[nx][ny] = false;
        }
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        list = new char[N][];
        visit = new boolean[N][M];
        alphachk = new boolean[26];
 
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            list[i] = st.nextToken().toCharArray();
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        dfs(001);
        System.out.println(ans);
    }
}
cs

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

boj 14500 테트로미노  (0) 2021.03.15
boj 16922 로마 숫자 만들기  (0) 2021.02.24
boj 3109 빵집  (0) 2021.02.18
boj 17406 배열 돌리기 4  (0) 2021.02.10
boj 16927 배열 돌리기 2  (0) 2021.02.10

www.acmicpc.net/problem/3109

 

3109번: 빵집

유명한 제빵사 김원웅은 빵집을 운영하고 있다. 원웅이의 빵집은 글로벌 재정 위기를 피해가지 못했고, 결국 심각한 재정 위기에 빠졌다. 원웅이는 지출을 줄이고자 여기저기 지출을 살펴보던

www.acmicpc.net

 

파이프는 오른쪽, 대각선 오른쪽 위, 대각선 오른쪽 아래 방향으로 연결할 수 있고,

0번 열에서 M - 1번 열까지 파이프를 이어야하며 최종적으로 파이프라인의 최대 갯수를 출력하는 문제입니다.

 

저는 여기서 앞의 열에서 최대한 앞쪽의 열에 파이프를 연결하면 될것이라는 생각을 하여 백트래킹에 그리디알고리즘을 사용하였습니다.

 

(0, 0) ~ (N - 1, 0)까지 각각 dfs로 끝 열에 도달할 수 있는지 확인해줍니다.

그리디를 사용했기때문에 오른쪽 위 -> 오른쪽 -> 오른쪽 아래 방향 순으로 탐색해줍니다.

끝 열에 도달하면 true를 리턴해주고, 도달하지 못하면 false를 리턴합니다.

true일 경우에만 ans++를 하여 최종 답을 출력합니다.

 

visit배열을 초기화하지 않은 이유는

파이프는 겹칠수 없어서 앞쪽에서 연결한 파이프와 겹칠 수 있기 때문입니다.

만약 최종적으로 연결한 파이프가 아니라고 해도 그 위치에서는 파이프를 연결할 수 없다는 뜻이 되므로 초기화를 하지 않아야합니다.

 

 

[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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
using namespace std;
 
bool visit[10010][510];
char list[10010][510];
int direct[3][2= { {-1,1},{0,1},{1,1} };
int N, M, ans;
 
bool dfs(int x, int y) {
    visit[x][y] = true;
    if (y == M - 1return true;
 
    for (int i = 0; i < 3; i++) {
        int nx = x + direct[i][0];
        int ny = y + direct[i][1];
 
        if (nx < 0 || ny < 0 || nx >= N || ny >= M) continue;
        if (visit[nx][ny] || list[nx][ny] == 'x'continue;
 
        bool chk = dfs(nx, ny);
        if (chk)
            return true;
    }
 
    return false;
}
 
void func() {
    for (int i = 0; i < N; i++) {
        if (dfs(i, 0)) ans++;
    }
 
    cout << ans << '\n';
}
 
void input() {
    cin >> N >> M;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> list[i][j];
        }
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

 

 

[Java]

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 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static int direct[][] = { { -11 }, { 01 }, { 11 } };
    static boolean visit[][];
    static char list[][];
    static int N, M, ans;
 
    static boolean dfs(int x, int y) {
        visit[x][y] = true;
        if (y == M - 1)
            return true;
 
        for (int i = 0; i < 3; i++) {
            int nx = x + direct[i][0];
            int ny = y + direct[i][1];
 
            if (nx < 0 || ny < 0 || nx >= N || ny >= M)
                continue;
            if (visit[nx][ny] || list[nx][ny] == 'x')
                continue;
 
            boolean chk = dfs(nx, ny);
            if (chk)
                return true;
        }
 
        return false;
    }
 
    static void func() {
        for (int i = 0; i < N; i++) {
            if (dfs(i, 0))
                ans++;
        }
 
        System.out.println(ans);
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        list = new char[N][];
        visit = new boolean[N][M];
 
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            list[i] = st.nextToken().toCharArray();
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

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

boj 16922 로마 숫자 만들기  (0) 2021.02.24
boj 1987 알파벳  (0) 2021.02.18
boj 17406 배열 돌리기 4  (0) 2021.02.10
boj 16927 배열 돌리기 2  (0) 2021.02.10
boj 16926 배열 돌리기 1  (0) 2021.02.10

www.acmicpc.net/problem/10157

 

10157번: 자리배정

첫 줄에는 공연장의 격자 크기를 나타내는 정수 C와 R이 하나의 공백을 사이에 두고 차례대로 주어진다. 두 값의 범위는 5 ≤ C, R ≤ 1,000이다. 그 다음 줄에는 어떤 관객의 대기번호 K가 주어진다.

www.acmicpc.net

문제의 그림은 이렇게 나와있지만

 

저는 편의를 위해 이렇게 옆으로 회전시켜서 구현하였습니다.

 

그 다음 (x, y) = (0, 0)으로 초기값을 잡고 시뮬레이션을 돌렸습니다.

진행방향은 오른쪽 -> 아래쪽 -> 왼쪽 -> 위쪽 순서입니다.

(nx ,ny)이 맵 밖으로 나가거나 방문한 좌표면 방향을 바꿔주고 다시 돌려줍니다.

이 과정에서 번호가 K에 도달하면 좌표를 출력해줍니다.

 

좌석은 N * M개 있으므로 만약 K가 N * M보다 크면 0을 출력하고 그냥 리턴시켜줍니다.

 

 

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
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 boolean visit[][];
    static int direct[][] = { { 01 }, { 10 }, { 0-1 }, { -10 } };
    static int N, M, K;
 
    static void func() {
        if (K > N * M) {
            System.out.println(0);
            return;
        }
 
        int x = 0;
        int y = 0;
        int idx = 0;
        for (int k = 1; k <= N * M; k++) {
            visit[x][y] = true;
            if (k == K) {
                System.out.println((x + 1+ " " + (y + 1));
                return;
            }
 
            int nx = x + direct[idx][0];
            int ny = y + direct[idx][1];
            if (nx < 0 || ny < 0 || nx >= N || ny >= M || visit[nx][ny]) {
                idx = (idx + 1) % 4;
                nx = x + direct[idx][0];
                ny = y + direct[idx][1];
            }
 
            x = nx;
            y = ny;
        }
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        st = new StringTokenizer(br.readLine());
        K = Integer.parseInt(st.nextToken());
        visit = new boolean[N][M];
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

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

boj 20055 컨베이어 벨트 위의 로봇  (0) 2021.02.23
boj 2331 반복수열  (0) 2021.02.23
boj 16918 봄버맨  (0) 2021.02.17
boj 16935 배열 돌리기 3  (0) 2021.02.10
boj 1914 하노이 탑  (0) 2021.02.07

www.acmicpc.net/problem/16918

 

16918번: 봄버맨

첫째 줄에 R, C, N (1 ≤ R, C, N ≤ 200)이 주어진다. 둘째 줄부터 R개의 줄에 격자판의 초기 상태가 주어진다. 빈 칸은 '.'로, 폭탄은 'O'로 주어진다.

www.acmicpc.net

1. 가장 처음에 봄버맨은 일부 칸에 폭탄을 설치합니다. (입력으로 주어집니다.)

2. 1초 후에 봄버맨은 아무것도 하지않습니다.

3. 다음 1초 후에 폭탄이 설치되어 있지 않은 모든 칸에 폭탄을 동시에 설치합니다.

4. 다음 1초 후에 3초전에 설치했던 폭탄이 터집니다. 이때 바로 옆 공간의 폭탄도 터집니다.

5. 이후 3과 4를 반복합니다.

 

저는 폭탄을 나타내는 char형 배열과 시간(카운트)를 나타내는 int형 배열을 사용하였습니다.

3번 4번 과정을 반복하고, 처음 1번과정은 입력으로 주어진 후 1초동안은 아무것도 하지않기때문에

K를 1빼주고 처음 입력으로 주어진 폭탄들의 시간은 2초로 해줍니다.

 

그리고 반복문은 2초부터 돌려줍니다.

폭탄은 짝수 초에 터지고, 홀수 초에 놓아지기때문에 홀, 짝으로 나누어 구현하였습니다.

 

폭탄을 놓을 때는 시간이 0인 모든 공간에 놓아주었고, 시간이 0이 아니면 1 감소시켰습니다.

폭탄을 터뜨릴 때는 터져야할 모든 폭탄을 덱에 넣고, bfs방식으로 인접한 폭탄들을 함께 터뜨렸습니다.

마지막으로 K초가 지난 후의 격자판 상태를 출력해주시면 됩니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static Deque<int[]> dq = new ArrayDeque<>();
    static int direct[][] = { { 01 }, { 10 }, { 0-1 }, { -10 } };
    static char list[][];
    static int time[][];
    static int N, M, K;
 
    static void print() {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++)
                sb.append(list[i][j]);
            sb.append("\n");
        }
 
        System.out.println(sb.toString());
    }
 
    static void bfs() {
        while (!dq.isEmpty()) {
            int x = dq.peekFirst()[0];
            int y = dq.pollFirst()[1];
            
            for (int k = 0; k < 4; k++) {
                int nx = x + direct[k][0];
                int ny = y + direct[k][1];
 
                if (nx < 0 || ny < 0 || nx >= N || ny >= M)
                    continue;
                time[nx][ny] = 0;
                list[nx][ny] = '.';
            }
        }
    }
 
    static void func() {
        for (int t = 1; t <= K; t++) {
            if (t % 2 != 0) {
                for (int i = 0; i < N; i++) {
                    for (int j = 0; j < M; j++) {
                        if (time[i][j] == 0) {
                            list[i][j] = 'O';
                            time[i][j] = 3;
                        } else
                            time[i][j]--;
                    }
                }
            } else {
                for (int i = 0; i < N; i++) {
                    for (int j = 0; j < M; j++) {
                        if (time[i][j] == 0)
                            continue;
                        time[i][j]--;
                        if (time[i][j] == 0) {
                            list[i][j] = '.';
                            dq.addLast(new int[] { i, j });
                        }
                    }
                }
 
                bfs();
            }
        }
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken()) - 1;
        time = new int[N][M];
        list = new char[N][M];
 
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            list[i] = st.nextToken().toCharArray();
            for (int j = 0; j < M; j++) {
                if (list[i][j] == 'O') {
                    time[i][j] = 2;
                }
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
        print();
    }
}
cs

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

boj 2331 반복수열  (0) 2021.02.23
boj 10157 자리배정  (0) 2021.02.17
boj 16935 배열 돌리기 3  (0) 2021.02.10
boj 1914 하노이 탑  (0) 2021.02.07
boj 11729 하노이 탑 이동 순서  (0) 2021.02.07

+ Recent posts