hihoCoder-1636

题意:

描述

In Chinese mythology, Pangu is the first living being and the creator of the sky and the earth. He woke up from an egg and split the egg into two parts: the sky and the earth.

At the beginning, there was no mountain on the earth, only stones all over the land.

There were N piles of stones, numbered from 1 to N. Pangu wanted to merge all of them into one pile to build a great mountain. If the sum of stones of some piles was S, Pangu would need S seconds to pile them into one pile, and there would be S stones in the new pile.

Unfortunately, every time Pangu could only merge successive piles into one pile. And the number of piles he merged shouldn’t be less than L or greater than R.

Pangu wanted to finish this as soon as possible.

Can you help him? If there was no solution, you should answer ‘0’.

输入

There are multiple test cases.

The first line of each case contains three integers N,L,R as above mentioned (2<=N<=100,2<=L<=R<=N).

The second line of each case contains N integers a1,a2 …aN (1<= ai <=1000,i= 1…N ), indicating the number of stones of pile 1, pile 2 …pile N.

The number of test cases is less than 110 and there are at most 5 test cases in which N >= 50.

输出

For each test case, you should output the minimum time(in seconds) Pangu had to take . If it was impossible for Pangu to do his job, you should output 0.

样例输入

3 2 2
1 2 3
3 2 3
1 2 3
4 3 3
1 2 3 4

样例输出

9
6
0

​ 翻译成汉语,大概意思就是给你三个数n,l,r,代表有n堆石子,之后一行有n个数,代表每堆石子的个数。每次只能把连续的l~r堆石子合并为1堆,若能最终把n堆石子合并为1堆,问最小花费是多少?不能合并为1堆则输出0。(l~r堆石子合并为1堆的花费是这些堆的石子数总和)

思路:

​ 这是一道区间dp题,做的时候一直在研究如何限制合并的堆数为l~r,想破头皮想出来区间DP嵌套dfs的做法,结果超时了。。。最后从网上看了题解,发现自己想问题想复杂了。我们设sum【i】为前i堆石子的石子数和,dp【i】【j】【k】代表区间i~j的石子堆合并成k堆所需要的最小花费,初始化为INF,然后对于dp【i】【j】【i - j + 1】初始化为0,对于dp【i】【i + len - 1】【1】初始化为sum【i + len - 1】 - sum【i - 1】。

​ 对于推导式,当k!=1时:

dp[i][j][k] = min(dp[i][j][k],dp[i][p][k - 1] + dp[p + 1][j][1]);	//其中p属于【i,j)

​ 我们在k!=1时其实不需要限制l~r的合并,因为此时没有合并操作,只是i~p有k - 1堆石子,(p + 1) ~

r有1堆石子,那么i~j有k堆石子,取最小的即可。至于为什么是k - 1 和 1项加,因为遍历全部的p,就包含i~j的所有合并可能且不重复了。因此我们只需要考虑当k == 1时的合并问题

​ 对于推导式,当k == 1时:

dp[i][j][1] = min(dp[i][j][1], dp[i][p][len - 1] + dp[p + 1][j][1] + sum[j] - sum[i - 1]); //其中p属于【i,j), len属于【l,r】

​ 因此,就可以用区间dp来求解,将酱~

代码;

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <algorithm>
#define d int32_t
#define ll int64_t
#define INF 0x3f3f3f3f
#define N 100
#define mem(a) memset(a, 0, sizeof(a))
#define For(i, star, endd) for(d i = star; i <= endd; i++)
using namespace std;

d a[N + 5];                     //每堆石子数
ll sum[N + 5];                  //前缀和
ll dp[N + 5][N + 5][N + 5];     //dp[i][j][k]代表区间i~j能合并成k堆的最小花费
d n, l, r;

//初始化
void init () {
    mem(sum);
    memset(dp, INF, sizeof(dp));
    For(i, 1, n) {
        scanf("%d", &a[i]);
        sum[i] = a[i] + sum[i - 1];
    }
    For(i, 1, n) {
        For(j, i, n) {
            dp[i][j][j - i + 1] = 0;
        }
    }
    For(i, l, r) {
        For(p, 1, n + 1 - i) {
            dp[p][p + i - 1][1] = sum[p + i - 1] - sum[p - 1];
        }
    }
}

void work () {
    For(len, 2, n) {
        For(i, 1, n - len + 1) {
            For(q, l, r) {
                For(p, i, i + len - 2) {
                    dp[i][i + len - 1][1] = min(dp[i][i + len - 1][1], dp[i][p][q - 1] + dp[p + 1][i + len - 1][1] + sum[i + len - 1] - sum[i - 1]);
                }
            }
            For(k, 2, len - 1) {
                For(p, i, i + len - 2) {
                    dp[i][i + len - 1][k] = min(dp[i][i + len - 1][k], dp[i][p][k - 1] + dp[p + 1][i + len - 1][1]);
                }
            }
        }
    }
}

d main() {
    while (scanf("%d%d%d", &n, &l, &r) == 3) {
        init();
        work();
        if ((d)dp[1][n][1] == INF) {
            printf("0\n");
        } else {
            printf("%lld\n", dp[1][n][1]);
        }
    }
    return 0;
}

转载请注明出处!!!

如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢

猜你喜欢

转载自blog.csdn.net/Ivan_zcy/article/details/83180561