문제

풀이 방법

겹치면 안된다. 따라서 다음과 같이 풀었다.(예제 입력인 3-10, 1,2,5로 설명)

1.전부 1로 채우는 경우

2.전부 1로 채우는 경우에 무조건 '2'가 한개 이상 들어가는 경우

3.전부 1,2로 채우는 경우에 무조건 '3'이 한개 이상 들어가는 경우

3까지 가면 완료이다!

코드

#include <iostream>
using namespace std;
int main()
{
    unsigned int dp[10001] = {0,};
    int arr[100] = { 0, };
    int n, k,x=0,y=1,r=0;
    cin >> n >> k;
    for (int i = 0; i < n; i++) cin >> arr[i];
    dp[0] = 1;
    for (int i = 0; i < n; i++) {
        for (int j = arr[i]; j <=k; j++) {
            dp[j] += dp[j - arr[i]];
        }
    }
cout << dp[k]<<endl;
    return 0;
}

'알고리즘 > 다이나믹프로그래밍' 카테고리의 다른 글

백준 10942번 팰린드롬  (0) 2019.02.08
백준 2225 합분해  (0) 2019.02.06
백준1699 제곱수의 합  (0) 2019.02.03
백준1912 연속합  (0) 2019.02.01
백준11053번 가장 긴 증가하는 부분 수열  (0) 2019.01.31

문제

접근 방안

dp문제이다.

처음 dp로 하지 않고 구현으로 하였다 틀렸다.

틀린 코드

#include "stdafx.h"
#include <iostream>
using namespace std;

int main()
{
    int input, input2;
    cin >> input;
    int arr[2001] = { 0, };
    for (int i=1; i<=input; i++) {
        cin >> arr[i];
    }
    cin >> input2;
    int *arr2 = new int[input2];
    int s,e,k=0,b=1;
    for (int i = 0; i < input2; i++) {
        b = 1;
        cin >> s >> e;
        while (s != e && s < e) {
            if (arr[s] != arr[e]) {
                b = 0;
                break;
            }
            s++;
            e--;
        }
        arr2[k] = b;
        k++;
    }
    for (int i = 0; i < input2; i++)
        cout << arr2[i]<<endl;

    return 0;
}

틀린 코드의 풀이 방식은 홍준이가 명준이에게 물어볼떄마다 일일이 아닌지 맞는지 찾았다.

당연히 시간초과. 이 문제의 핵심은 0.5초이다.

풀이방법

if(arr[i]==arr[i+j] && dp[i+1][i+j-1]==1)
dp[i][i+j]=1;

즉 i와 i+j가 같은데 그 사이 값이 팰린드롬이면 i~i+j까지는 팰린드롬이라는 의미이다.

문제에서 실수한 부분

cin, cout을 쓰면 시간 초과가 되어 printf, scanf를 써야한다.

scanf_s, printf_s로 하면 컴파일 에러가 나니 scanf,printf로 쓰도록 한다.

코드

#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
    int input, input2;
    scanf("%d", &input);
    int arr[2001] = { 0, };

    for (int i = 1; i <= input; i++) {
        cin >> arr[i];
    }

    int s, e, k = 0, b = 1;
    int **dp;
    int c, l;
    dp = new int *[input + 1];
    for (int i = 0; i <= input; i++) {
        dp[i] = new int[input + 1]();
    }

    for (int i = 1; i < input; i++) {
        dp[i][i] = 1;
        if (arr[i] == arr[i + 1])dp[i][i + 1] = 1;
    }
    dp[input][input] = 1;
    int x = 1;
    for (int j = 2; j <= (input - 1); j++) {
        for (int i = 1; i <= (input - j); i++) {
            if (arr[i] == arr[i + j]&&dp[i+1][i+j-1])
                dp[i][i + j] = 1;
        }
    }

    cin >> input2;
    int *arr2 = new int[input2];

    for (int i = 0; i < input2; i++) {
        scanf("%d %d", &s, &e);
        printf("%d\n", dp[s][e]);
    }
    return 0;
}

문제

풀이방법

떠오르지 않아 직접 표를 만들어 보았다.

예상외로 점화식은 dp[n][k]=dp[n][k-1]+dp[n-1][k]로 간단하였다.

코드

#include <iostream>
#define mod 1000000000
using namespace std;

int main()
{
    unsigned int dp[203][203] = { 0, };
    int i = 0, j = 0, n = 0, k = 0;
    cin >> n;
    cin >> k;
    for (i = 1; i <= n; i++) {
        dp[i][1] = 1;
    }
    for (i = 1; i <= k; i++)
        dp[1][i] = i;
    for (i = 2; i <= n; i++) {
        for (j = 2; j <= k; j++)
            dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % mod;
    }
    cout << dp[n][k];
    return 0;
}

문제

해결방법

step1. 1,4,6,9같은 제곱수에 1을 넣어준다.

step2. 나머지 숫자들을 찾아준다.

for (a = 1; a <=sqrt(i); a++) {
#dp[i]를 구하고자한다.
#min( dp[i-1^2]+1, dp[i-2^2]+1, dp[i-3^2]+1....dp[i-sqrt(i)^2] ) 이다.
                if (dp[i - a * a] < minx)

                minx = dp[i - a * a];

            }

dp[i] = minx + 1;

코드

#include <iostream>
#include <math.h>
#include <algorithm>
using namespace std;
int main()
{
    int input;
    int dp[100010];
    cin >> input;
    dp[1] = 1;
    int a;
    int minx;
    int i, j;
    for (i = 1; i <= sqrt(input); i++) {
        dp[i*i] = 1;
    }
    for (i = 2; i <= input; i++) {
        if (dp[i] == 1)
            continue;
        else {
            minx = 100001;
            for (a = 1; a <=sqrt(i); a++) {
                if (dp[i - a * a] < minx)
                    minx = dp[i - a * a];
            }
            dp[i] = minx + 1;
        }
    }
    cout <<dp[input];
    return 0;
}

'알고리즘 > 다이나믹프로그래밍' 카테고리의 다른 글

백준 10942번 팰린드롬  (0) 2019.02.08
백준 2225 합분해  (0) 2019.02.06
백준1912 연속합  (0) 2019.02.01
백준11053번 가장 긴 증가하는 부분 수열  (0) 2019.01.31
백준11057 오르막 수  (0) 2019.01.30

문제

풀이방법

dp[i]=max(dp[i-1]+arr[i],arr[i])

주의할점

배열 초기화 및 배열 넉넉히 세팅

음수가 배열에 들어가니 기준값 잘 설정하기

코드


// bj1912.cpp: 콘솔 응용 프로그램의 진입점을 정의합니다.
//
#include "stdafx.h"
#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
    long arr[100001] = {0,};
    long dp[100001] = {0,};
    int input;
    long maxval=0;
    cin >> input;
    int i, j, k;

    for (i = 0; i < input; i++)
        cin >> arr[i];

    dp[0] = arr[0];
    for (i = 1; i < input; i++) {

        dp[i] = max(dp[i - 1] + arr[i], arr[i]);


    }

    maxval = dp[0];

    for (i = 0; i < input; i++) {
    if (maxval < dp[i])
            maxval = dp[i];
    }

    cout << maxval;
    return 0;
}

'알고리즘 > 다이나믹프로그래밍' 카테고리의 다른 글

백준 2225 합분해  (0) 2019.02.06
백준1699 제곱수의 합  (0) 2019.02.03
백준11053번 가장 긴 증가하는 부분 수열  (0) 2019.01.31
백준11057 오르막 수  (0) 2019.01.30
백준1563 개근상  (0) 2019.01.30

문제

풀이 방법

예를 들어 설명 하겠다

ㅁㅁㅁㅁㅁㅁㅁㅁㅁ20ㅁㅁㅁㅁㅁ

이런식으로 있으면

20앞에 있는 수중 20보다 작은 가장 가까운 수가 있을것이다.

그렇다면 20까지 왔을때 가장 긴 증가하는 수열의 길이는

20보다 작은 가장 가까운 수의 +1 이 된다.

예를들어

10 20 10 30 20 50

에서 30까지 왔을때 30을 포함하는 가장 긴 수열의 길이는 30보다 작은 수중 가장 큰 수인

20에 +1을 한것이다.

코드

#include <iostream>
using namespace std;

int main()
{
    int input;
    cin >> input;
    int arr[1001] = {0,};
    int dp[1001] = {0,};
    int i,j;
    int min=0;
    int maxv;
    int max=0;
    for (i = 0; i < input; i++) {
        cin >> arr[i];
        dp[i] = 0;
    }
    for (i = 0; i < input; i++) {
        min = 0;
        for (j = 0; j < i; j++) {
            if (arr[j] < arr[i] && min < dp[j]) {
                min = dp[j];
            }
        }
        dp[i] = min + 1;
        if (max < dp[i]) max = dp[i];
    }
    cout <<max;
    return 0;
}

'알고리즘 > 다이나믹프로그래밍' 카테고리의 다른 글

백준1699 제곱수의 합  (0) 2019.02.03
백준1912 연속합  (0) 2019.02.01
백준11057 오르막 수  (0) 2019.01.30
백준1563 개근상  (0) 2019.01.30
백준11052 카드 구매하기  (0) 2019.01.25

문제

접근 방안

자릿수가 k 일때 1ㅁㅁㅁㅁ 이면
이때의 오르막수 갯수를 k_1이라 하면
k_1은 (k-1)_1+(k-1)_2+(k-1)_3+(k-1)_4+(k-1)_5+....(k-1)_9가 된다.
k_2는 (k-1)_2+(k-1)_3+(k-1)_4+(k-1)_5+....(k-1)_9
...
k_9는 (k-1)_9가 된다.
이를 모조리 합쳐주면 된다.
따라서 배열 dp는

dp[자릿수][9]
로 만들면 된다.

코드


#include <iostream>
using namespace std;

int main()
{
    int i;
    int row, col;
    row = 0; col = 0;
    int input;
    cin >> input;
    int** arry;
    arry = new int *[input];
    int y;
    for (i = 0; i < input; i++) {
        arry[i] = new int[10];
    }

    for (i = 0; i < 10; i++) {
        arry[0][i] = 1;
    }

    for (row = 1; row < input; row++) {
        for (col = 0; col < 10; col++) {
            y = 0;
            for (i = col; i < 10; i++) {
                y = (arry[row - 1][i] + y)%10007;
            }
            arry[row][col] = y;
        }
    }
    int result=0;
    for (col = 0; col < 10; col++) {
        result = (result + arry[input - 1][col]) % 10007;
    }
    cout << result;

    return 0;
}

'알고리즘 > 다이나믹프로그래밍' 카테고리의 다른 글

백준1912 연속합  (0) 2019.02.01
백준11053번 가장 긴 증가하는 부분 수열  (0) 2019.01.31
백준1563 개근상  (0) 2019.01.30
백준11052 카드 구매하기  (0) 2019.01.25
백준10844 쉬운 계단 수  (0) 2019.01.25

문제

해결방안

dp[출석일수][지각수][연속빠진수]
로 일단 배열을 세팅한다.

1)ㅁㅁㅁㅁㅁ출석 (맨마지막날 출석한 경우)
dp[출석일수][지각수][0]
=dp[출석일수-1][지각수][0,1,2] #연속빠진수는 어차피 마지막날 출석이면 0으로 초기화

2)ㅁㅁㅁㅁㅁ지각 (맨마지막날 지각한 경우)
dp[출석일수][1][0]=dp[출석일수-1][0][0,1,2] #맨마지막날 지각하면 어차피 연속빠진수는 0으로 초기화 됨

3)ㅁㅁㅁㅁㅁ연속빠진수 (맨마지막날 결석한 경우)
dp[출석일수][0][2]=dp[출석일수-1][0][1]
dp[출석일수][0][1]=dp[출석일수-1][0][0]
dp[출석일수][1][2]=dp[출석일수-1][1][1]
dp[출석일수][1][1]=dp[출석일수-1][1][1]

코드

#include <iostream>
int mod = 1000000;
using namespace std;

int main()
{
    int k;
    int ***dp;
    int x,y,z;
    int i,j,m;
    int result = 0;;
    cin >> x;
    dp = new int **[x+1];

    for (i = 0; i < x+1; i++) {
        dp[i] = new int *[2];
        for (j = 0; j < 2; j++) {
            dp[i][j] = new int[3];
        }
    }

    for (i = 0; i < x + 1; i++) {
        for (j = 0; j < 2; j++) {
            for (m = 0; m < 3; m++) {
                dp[i][j][m] = 0;
            }
        }
    }


    dp[0][0][0] = 1;
    dp[1][0][0] = 1;
    dp[1][0][1] = 1;
    dp[1][1][0] = 1;

    for (i = 2; i < x + 1; i++) {
        for (j = 0; j < 2; j++) {
            for (k = 0; k < 3; k++) {
                dp[i][j][0] += dp[i - 1][j][k];
                dp[i][j][0] %= mod;
                if (k < 2) {
                    dp[i][j][k + 1] += dp[i - 1][j][k];
                    dp[i][j][k + 1] %= mod;
                }
                if (j == 0) {
                    dp[i][1][0] += dp[i - 1][0][k];
                    dp[i][1][0] %= mod;
                }
            }
        }
    }
    for (j = 0; j < 2; j++) {
        for (m = 0; m < 3; m++) {
            result += dp[x][j][m];
        }
    }

    cout << result%mod;

    return 0;
}

문제

풀이

#include <iostream>
#include <algorithm>
using namespace std;

int main() {

    int *arrx;
    int input;
    int i = 0;
    int m, n;
    int *arry;
    int max=0;

    cin >> input;
    arrx = new int[input+1];
    arry = new int[input+1];
    arrx[0] = 0;
    arry[0] = 0;

    for (i = 1; i <= input; i++) {
        cin >> arrx[i];
        arry[i] = 0;
    }

    for (m = 1; m <= input; m++) {
        for (n = 1; n <= input; n++) {
            if (m - n >= 0)
                if (max < arry[m - n] + arrx[n])
                    max = arry[m - n] + arrx[n];
        }
        arry[m] = max;
        max = 0;
    }
    cout <<arry[input];

    return 0;
}

풀이방법

간단한 다이나믹 프로그래밍이다.
예를 들어
카드가 2장 있으면 1+1
3장 있으면 max(1+2,3)
4장 있으면 max(1+3,2+2,4)
이런식으로 구해주면 끝!

'알고리즘 > 다이나믹프로그래밍' 카테고리의 다른 글

백준11057 오르막 수  (0) 2019.01.30
백준1563 개근상  (0) 2019.01.30
백준10844 쉬운 계단 수  (0) 2019.01.25
백준 11727 2Xn 타일링 2  (2) 2018.11.07
백준 9095번 1,2,3더하기  (0) 2018.11.07

문제

풀이

#include <iostream>
using namespace std;

int main() {
    int input;
    cin >> input;
    int **arry;
    arry = new int *[input+1];
    int i = 0;
    int r, c;
    int result=0;

    for (i = 0; i <= input; i++)
        arry[i] = new int[10];

    for (i = 0; i < 10; i++) {
        arry[0][i] = 0;
        arry[1][i] = 1;
    }
    arry[1][0] = 0;

    for (i = 0; i <= input; i++)
        arry[i][0] = 0;

    if (input > 1) {

        for (i = 1; i <= 8; i++) {
            arry[2][i] = 2;
        }

        arry[2][9] = 1;

        for (r = 3; r <= input; r++) {
            for (c = 1; c <= 9; c++) {
                if (c - 1 == 0)
                    arry[r][c] = (arry[r - 2][1] + arry[r - 1][2])% 1000000000;
                else if (c + 1 == 10)
                    arry[r][c] =( arry[r - 1][8])% 1000000000;
                else
                    arry[r][c] = (arry[r - 1][c - 1] + arry[r - 1][c + 1])% 1000000000;
            }
        }
    }
    for (c = 0; c <= 9; c++)
        result = (result + arry[input][c])%1000000000;

    cout << result% 1000000000;

    return 0;
}

풀이방법

예를들어 생각해 보자
3자리수를 구하고자 할때
1ㅁㅁ
2ㅁㅁ
3ㅁㅁ
4ㅁㅁ
5ㅁㅁ
6ㅁㅁ
7ㅁㅁ
8ㅁㅁ
9ㅁㅁ
이 나올 수 있다.
이때 ㅁㅁ은
2자리 수에서 구할 수 있다.
즉 여기서 다이나믹 프로그래밍임을 알 수 있다.

다시 예제로 돌아와서.
3ㅁㅁ의 경우 32ㅁ or 34ㅁ이다.
1)즉 D[R][C] = D[R-1][C+1]+D[R-1][C-1]이다. (R은 자릿수, C는 0~9의 수)
2)첫째 자리가 1인 경우는 D[R-2][1]+D[R-1][2]
3)첫째 자리가 9인 경우는 D[R-1][8]만 된다.

1)즉 D[R][C] = D[R-1][C+1]+D[R-1][C-1]이다. (R은 자릿수, C는 0~9의 수)

2)첫째 자리가 1인 경우는 D[R-2][1]+D[R-1][2]

3)첫째 자리가 9인 경우는 D[R-1][8]만 된다.

문제를 풀며 1000000000으로 나누는것을 주의 하자. 생각보다 수가 엄청 커진다

'알고리즘 > 다이나믹프로그래밍' 카테고리의 다른 글

백준1563 개근상  (0) 2019.01.30
백준11052 카드 구매하기  (0) 2019.01.25
백준 11727 2Xn 타일링 2  (2) 2018.11.07
백준 9095번 1,2,3더하기  (0) 2018.11.07
[백준11726번 - 2xn 타일링]  (0) 2018.11.03

+ Recent posts