DP 알고리즘 - POJ 4119 : 복잡한 정수 분할 문제

이름

총 제한 시간 : 메모리 제한 200MS : 65536kB이
설명
은 양의 정수를, n은 양의 정수의 시리즈를 나타내고, N = N1 + N2 + ... + NK, 여기서 N1> = N2> = ...> = NK> = 1, K> = 1 .
이것은 양의 정수를 나타내고, n은 양의 정수를 n 개의 분할 불린다.

입력
테스트 데이터의 복수의 세트를 포함하는 표준 입력. 각 시험은 두 정수 N과 K.를 포함하는, 입력 데이터의 라인
(0 <N <= 50, 0 <K <= N)
의 출력
각 테스트 데이터 출력의 다음 세 라인 :
제 라인 : N은 양의 정수 K 및로 분할되어
두 번째 행 : N 분할 숫자는 여러 가지 양의 정수와로 분할
번째 행 : N이 홀수 및 양의 정수 분할로 분할되는
샘플의 입력
(52)
의 샘플 출력
(2)
. (3)
. (3)

첫번째 라인 : 4 + 1, 3 + 2
번째 줄 : 5,4 + 1,3 + 2
행 3 : 1 + 5,1 + 3, 1 + 1 + 1 + 1 + 1 + 1

첫 번째 질문

: 제약 K 전에 문제보다 정수 분할 문제는,이 문제는 배낭 문제로 유추 될 수 있으며,이 문제는 다음으로 변환되어
K 개의 숫자 [1 ... N]을 선택하고 N 인으로부터 선택된 숫자는 일반적인 동적 프로그래밍 문제이며, 이는 반복 될 수있다.
[I 1 ...] 선택된 개수 Q에서 다음 하위 문제를 고려하고있는 J.
주문 F [I] [J] [ Q] 솔루션 하위 문제도.
다음의 경계 조건을 고려한다 : 1 인 [1 ... 1]에서 번호, 그룹 F로부터 선택되는 유일한 방법을 선택 [1] [1] [ 1] = 1,
다음으로 상태 천이를 고려 :
F를 [I] [J] [Q] = F [. I-1] [J] [Q] + F [I]를 [J - 전] [Q -. 1]
[. I-1] F는 [J] [Q]는 제 i 번째를 나타낸다 숫자는 다음의 질문 번호를 선택, 선택되지 않은 I-1 및 J 인 이전
F [내가] - [Q - 1] i 번째 선택된 후 전면 선택된 번호 I Q-1을 나타내고, [J는 I]를 A, i가 문제의 서브 - I, 즉 각각의 선택된 번호에 사용될 수 있기 때문에 I-1을 촬영없는 고유하지 JI가 인
것이 일반 배낭 문제의 특수한 경우이다.
이러한 방법으로, 기록 동적 계획 프로세스에 세 자리 그룹을 사용하여이 문제의 해결책은 될 수 있지만, 일부 계획은 동적 배열은,이 도로가 될 수있는 공간을 절약하기 위해 스크롤하는 데 사용할 수 있습니다.
첫 번째 사이클 난을 시작하기 전에 이전 사이클의 층 [J] F 두자리 [Q]의 그룹 난 [J] F를, 선택의 수를 나타낸다고 가정한다 [Q]는 전방 선택된 1 난의 수를 나타낸다 F에 대해, J는 Q를 구성하는 [I] [지] [ Q-1]
때문에 이송 전에 F [I] [J] [ Q] 위해, F [지 η] = [Q - 1]에 : i 번째주기 갱신 값, 상태 천이가 단순화 될 수 있도록한다는 것이다
F는 [J]를 [Q] + = F는 [JI] -Q 1.]
코드의이 부분은 다음과 같다 :

dp[0][0] = 1;
for (int i = 1; i <= n; i++)
    for (int j = i; j <= n; j++)
	for (int q = k; q >= 1; q--)
	    dp[j][q] += dp[j - i][q - 1];
printf("%d\n", dp[n][k]);

두 번째 질문

: 간단한 디지털 정수 나눗셈 문제의 증가 전에 두번째 문제는 상태 천이 식 반사 제한 내부에 반복 될 수없는
집합 F [I]는 [j]가 이전의 해시 I의 J의 수이고
상태 천이 방정식 :
F [I] [J] = F [I-1] [지] + F [I-1] [J]
마찬가지로, 2 차원 어레이가 주목하여야 차원으로 스크롤 할 수있는 이송 내림차순 J
코드 :

dp1[0] = 1;
        for (int i = 1; i <= n; i++)
            for (int j = n; j >= i; j--)
                dp1[j] += dp1[j - i];
        printf("%d\n", dp1[n]);

세 번째 질문

단지 양의 홀수, 메모를 선택할 수 있습니다 정수 분할 문제에 간단한 증가보다 세 번째 질문 한 후, 디지털 스틸이 사실을 이해, 반복, 처음 두 질문을 작성하는 매우 좋은
상태 전이 방정식을 쓰고 직접 :
F [ I] [J] = F [I]를 [J - I]를 + F는 [I-2] [J]
... F [1] [1] = 1
어레이를 압연 후, 난 홀수 탐색을 수행함으로써, J 작은에서 필요한 대형 횡단 .
코드 :

dp2[0] = 1;
        for (int i = 1; i <= n; i += 2)
            for (int j = i; j <= n; j++)
                dp2[j] += dp2[j - i];
        printf("%d\n", dp2[n]);

코드 전체 질문 :

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

typedef long long ll;

const int N = 50 + 5;
int dp[N][N], dp1[N], dp2[N];

int main() {
    for (int n, k; scanf("%d%d", &n, &k) == 2;) {
        memset(dp, 0, sizeof(dp));
        memset(dp1, 0, sizeof(dp1));
        memset(dp2, 0, sizeof(dp2));
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++)
            for (int j = i; j <= n; j++)
                for (int q = k; q >= 1; q--)
                    dp[j][q] += dp[j - i][q - 1];
        printf("%d\n", dp[n][k]);
        dp1[0] = 1;
        for (int i = 1; i <= n; i++)
            for (int j = n; j >= i; j--)
                dp1[j] += dp1[j - i];
        printf("%d\n", dp1[n]);
        dp2[0] = 1;
        for (int i = 1; i <= n; i += 2)
            for (int j = i; j <= n; j++)
                dp2[j] += dp2[j - i];
        printf("%d\n", dp2[n]);
    }
    return 0;
}

참조 코드 : https://blog.csdn.net/Nightmare_ak/article/details/94414363

추천

출처www.cnblogs.com/zhangyue123/p/12557503.html