HihoCoder - 1636 Pangu and Stones - 구간 dp

2058 단어 동적 기획
제목: 돌의 합병을 토대로 제한을 하여 매번 적어도 l더미의 돌을 합병하고 r더미의 돌을 많이 합병하도록 규정한다.
사고방식: dp[i][j][k]를 구간[i, j]으로 정의하고 k가 돌을 쌓을 때의 최소치를 포함한다. 최종 결과는 dp[1][n][1]이다. 즉, 전체 구간이 최종적으로 1무더기의 최소치로 통합되고 뚜렷한 dp[i][j][1]이 해답의 중점이다.
dp[i][j][1]의 상태 전이 방정식을 풀려면 dp[i][j][1]=min(dp[i][j][1], dp[i][j]][k]+sum[j]-sum[i-1])))(2<=k<=r(r는 제목이 정해진 것이다))
그 중에서sum[]예처리 접두사와 임의의 연속 구간의 합을 계산하는 데 사용되는 것은 구간 [i, j] 중의 모든 더미를 1개의 더미로 합치려면 어쨌든 이 구간의 총계를 써야 한다. dp[i][j][k](2 <=k<=r)는 각각 다른 구분을 하고 최종적으로 최소치를 찾는다.
dp[i][j][k](2 <=k>=r)의 상태 전이 방정식은 dp[i][j][k]=min(dp[i][j]][k], dp[i][p][1]+dp[p+1][j][k-1]))(i<=pp는 구간 [i, j]을 모두 반으로 나누면 dp[i][j][k]는 왼쪽 [i, p]를 1무더기, 오른쪽 [p+1, j]를 k-1무더기로 나누어 옮긴다. 왜 sum[j]-sum[i-1]을 넣지 않는지는 우리의 합병 과정이 dp[i][j][1]에서 이루어졌기 때문이다.dp[i][j][k](2 에서 우리는 구분만 책임지고 합병을 하지 않는다. 이것도 이 문제의 교묘한 점이다.
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 105;
const int INF = 0x3f3f3f3f;
int n, l, r, a[maxn], sum[maxn], dp[maxn][maxn][maxn];
int main() {
    while (~scanf("%d %d %d", &n, &l, &r)) {
        sum[0] = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            sum[i] = sum[i-1] + a[i];
        }
        memset(dp, INF, sizeof(dp));
        for (int i = 1; i <= n; i++) dp[i][i][1] = 0;
        for (int len = 1; len <= n; len++) {
            for (int i = 1; i + len - 1 <= n; i++) {
                int j = i + len - 1;
                for (int k = min(r, len); k >= 2; k--) {
                    for (int p = i; p < j && j - p >= k - 1; p++) {
                        dp[i][j][k] = min(dp[i][j][k], dp[i][p][1] + dp[p+1][j][k-1]);
                    }
                    if (k >= l) dp[i][j][1] = min(dp[i][j][1], dp[i][j][k] + sum[j] - sum[i-1]);
                }
            }
        }
        printf("%d
", dp[1][n][1] == INF ? 0 : dp[1][n][1]); } return 0; }

좋은 웹페이지 즐겨찾기