https://www.acmicpc.net/problem/9465




풀이


2행 n열로 구성되어있는 스티커이기 때문에 2차원 배열을 이용해서 dp로 구하기로 한다.

dp[i][j] 는 arr[i][j]까지의 스티커 배열 중에 스티커를 골라 최대값이 나올 수 있게 골라 더한 값을 담는다고 하자.



i)


arr[1][1]    arr[1][2]   arr[1][3]    arr[1][4]    arr[1][5]

arr[2][1]   arr[2][2]    arr[2][3]    arr[2][4]    arr[2][5]            ===>    dp[1][4] = dp[2][2] + arr[1][4];

vs

arr[1][1]    arr[1][2]   arr[1][3]    arr[1][4]    arr[1][5]

arr[2][1]   arr[2][2]    arr[2][3]    arr[2][4]    arr[2][5]            ===>     dp[1][4] = dp[2][3] + arr[1][4];


dp[1][4] = max(dp[2][2] + arr[1][4] , dp[2][3] + arr[1][4]);




ii)

arr[1][1]    arr[1][2]   arr[1][3]    arr[1][4]    arr[1][5]

arr[2][1]   arr[2][2]    arr[2][3]    arr[2][4]    arr[2][5]            ===>    dp[2][4] = dp[1][2] + arr[2][4];

vs

arr[1][1]    arr[1][2]   arr[1][3]    arr[1][4]    arr[1][5]

arr[2][1]   arr[2][2]    arr[2][3]    arr[2][4]    arr[2][5]            ===>    dp[2][4] = dp[1][3] + arr[2][4];


dp[2][4] = max(dp[1][2] + arr[2][4] , dp[1][3] + arr[2][4]); 



위와 같은 방법으로 모든 스티커에 대해 dp를 구해 나가고 마지막 배열 dp[1][N], dp[2][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
#include <stdio.h>
 
#define Max(a,b) a>b ? a:b
 
int main(){
    int T, N;
    int arr[3][100001= { 0 };
    int dp[3][100001= { 0 };
    
    scanf("%d"&T);
    for(int i=1; i<=T; i++){
        scanf("%d"&N);
        for(int k=1; k<=2; k++){
            for(int j=1; j<=N; j++){
                scanf("%d"&arr[k][j]);
            }
        }
        dp[1][1= arr[1][1];
        dp[2][1= arr[2][1];
        dp[2][2= arr[1][1+ arr[2][2];
        dp[1][2= arr[2][1+ arr[1][2];
        for(int j=3; j<=N; j++){
            dp[1][j] = Max(dp[2][j-1+ arr[1][j], dp[2][j-2+ arr[1][j]);
            dp[2][j] = Max(dp[1][j-2+ arr[2][j], dp[1][j-1+ arr[2][j]);
        }
        printf("%d\n", Max(dp[1][N], dp[2][N]));
        
    }
    return 0;
}
cs



'알고리즘' 카테고리의 다른 글

(2167)(DP) 백준 2차원 배열의 합  (0) 2018.07.30
(9461)(DP) 파도반 수열  (0) 2018.07.30
(2293)(DP) 백준 동전1  (0) 2018.07.23
(1010)(DP) 백준 다리놓기  (0) 2018.07.15
(11727)(DP) 백준 2xn 타일링 2  (0) 2018.07.15

https://www.acmicpc.net/problem/2293





풀이


n가지 종류의 서로 다른 값의 동전을 주고 각 동전들을 적당히 사용해서, 그 가치의 합이  k원이 되도록 할 때 총 경우의 수를 구하는 문제이다. 

각각의 동전은 몇개라도 사용해서 k원을 만들면 된다.


예를 들어서 coin[1] = 1, coin[2] = 2, coin[3] = 5 의 3가지 동전이 주어졌고 10을 만드는 총 경우의 수를 구해야 한다고 하면

먼저 1을 만들 수 있는 경우의 수부터 2를 만들 수 있는 경우 , 3, 4, .... 이런식으로 dp[j]에 coin[i] 순서대로 구해 저장 해놓기로 한다.


int dp[10001] = { 0 }; 

dp[0] = 1;


1을 만들 수 있는 경우 1  (1 가지) 1. dp[1] = dp[1] + dp[1 - coin[1]];

2를 만들 수 있는 경우 (1)-1 / 2 ( 1 + 1 가지) 2. dp[2] = dp[2] + dp[2 - coin[1]];     /   6.  dp[2] = dp[2] + dp[2 - coin[2]];

3을 만들 수 있는 경우 (1-1)-1 / (1)-2 (1 + 1 가지) 3. dp[3] = dp[3] + dp[3 - coin[1]];    /  7.  dp[3] = dp[3] + dp[3 - coin[2]];

4를 만들 수 있는 경우 (1-1-1)-1 / (1-1)-2 / (2)-2 (1 + 2 가지) 4. dp[4] = dp[4] + dp[4 - coin[1]];    /    8. dp[4] = dp[4] + dp[4 - coin[2]];

5를 만들 수 있는 경우 (1-1-1-1)-1 / (1-1-1)-2 / (1-2)-2 / 5 (1 + 2 + 1 가지) 5. dp[5] = dp[5] + dp[5 - coin[1]];    /    9. dp[5] = dp[5] + dp[5 -coin[2]];    /    10. dp[5] = dp[5] + dp[5 - coin[3]] ;

.

.

.

이런 식으로  순차적으로 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
#include<stdio.h>
int main(){
int arr[101= { 0 };
int dp[10001= { 0 };
int N, K;
 
scanf("%d %d\n"&N, &K);
 
for(int i=1; i<=N; i++){
    scanf("%d"&arr[i]);
}
 
dp[0= 1;
 
for(int i=1; i<=N; i++){
    for(int j=1; j<=K; j++){
        if(j >= arr[i]){
            dp[j] += dp[j - arr[i]];
        }
    }
}
 
printf("%d\n", dp[K]);
 
return 0;
}
 
 
 
cs

 

'알고리즘' 카테고리의 다른 글

(9461)(DP) 파도반 수열  (0) 2018.07.30
(9465)(DP) 백준 스티커  (0) 2018.07.30
(1010)(DP) 백준 다리놓기  (0) 2018.07.15
(11727)(DP) 백준 2xn 타일링 2  (0) 2018.07.15
(11053)(DP) 백준 가장 긴 증가하는 부분 수열  (0) 2018.07.14

https://www.acmicpc.net/problem/1010




풀이


i개의 서쪽 사이트와 j개의 동쪽 사이트를 잇는 다리를 지을 수 있는 경우의 수 dp[i][j]라고 하자.



dp[1][1]

dp[1][2]    dp[2][2]

dp[1][3]    dp[2][3]    dp[3][3]

dp[1][4]    dp[2][4]    dp[3][4]    dp[4][4]

.

.

.

이런식으로 dp[N][M]까지의 dp를 모두 구할 것이다.


이해하기 쉽게 예를 들어보기로 한다.



ex) 사이트에 번호를 메기고 dp[2][4]의 다리를 놓는 경우의 수를 알고싶다. 


1과 2의 경우로 나누어 생각해보자 


1번의 경우


먼저 그림의 1번 경우와 같이 2-4를 잇게 되면 N-1 개의 사이트와 M-1개의 사이트를 잇는 경우의 수를 구하는 꼴이 된다.

 즉, dp[1][3]의 값이라고 할 수 있다.


2번의 경우


다음은 그림의 2번 경우와 같이 2-3을 잇게되면 N개의 사이트와 M-1개의 사이트를 잇는 경우의 수를 구하는 꼴이 된다.

즉, dp[2][3]의 값이라고 할 수 있다.


dp[N][M] = dp[N-1][M-1] + dp[N][M-1];

위처럼 모든 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
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
 
 
int main() {
    int dp[31][31= { 0 };
    int n, N, M;
 
    scanf("%d"&n);
 
    for (int i = 1; i <= n; i++) {
        scanf("%d %d\n"&N, &M);
    
            for (int i = 1; i <= M; i++) {
                dp[1][i] = i;
                for (int j = 2; j <= i; j++) {
                    dp[j][i] = dp[j - 1][i - 1+ dp[j][i - 1];
                
                }
            }
        printf("%d\n", dp[N][M]);
    }
 
    return 0;
 
}
cs


+ Recent posts