HihoCoder 1636 Pangu and Stones(区间DP)题解
题意:合并石子,每次只能合并l~r堆成1堆,代价是新石堆石子个数,问最后能不能合成1堆,不能输出0,能输出最小代价
思路:dp[l][r][t]表示把l到r的石堆合并成t需要的最小代价。
当t == 1时,dp[i][j][1] = min(dp[i][j][1], dp[i][k][t] + dp[k + 1][j][1] + sum[j] - sum[i - 1]),其中t属于[l - 1, r - 1]
当t >= 2时,dp[i][j][t] = min(dp[i][j][t], dp[i][k][t - 1] + dp[k + 1][j][1])。
初始化:
for(int i = 1; i <= n; i++){ for(int j = i; j <= n; j++){ dp[i][j][j - i + 1] = 0; } }
代码:
#include<cstdio> #include<cstring> #include<algorithm> typedef long long ll; using namespace std; const int maxn = 100 + 10; const int MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; int a[maxn], dp[maxn][maxn][maxn], sum[maxn]; int main(){ int n, l, r; while(~scanf("%d%d%d", &n, &l, &r)){ sum[0] = 0; for(int i = 1; i <= n; i++){ scanf("%d", &a[i]); sum[i] = a[i] + sum[i - 1]; } memset(dp, INF, sizeof(dp)); for(int i = 1; i <= n; i++){ for(int j = i; j <= n; j++){ dp[i][j][j - i + 1] = 0; } } for(int len = 2; len <= n; len++){ for(int i = 1; i + len - 1 <= n; i++){ int j = i + len - 1; for(int k = i; k < j; k++){ for(int t = l - 1; t <= r - 1; t++){ dp[i][j][1] = min(dp[i][j][1], dp[i][k][t] + dp[k + 1][j][1] + sum[j] - sum[i - 1]); } } for(int t = 2; t <= len; t++){ for(int k = i; k < j; k++){ dp[i][j][t] = min(dp[i][j][t], dp[i][k][t - 1] + dp[k + 1][j][1]); } } } } if(dp[1][n][1] >= INF) printf("0\n"); else printf("%d\n", dp[1][n][1]); } return 0; }