HihoCoder - 1636 Pangu and Stones(區間DP)
阿新 • • 發佈:2018-09-03
algorithm sca 問題 con -s 轉移 one nes iostream
有n堆石子,每次你可以把相鄰的最少L堆,最多R堆合並成一堆。
問把所有石子合並成一堆石子的最少花費是多少。
如果不能合並,輸出0。
石子合並的變種問題。
用dp[l][r][k]表示將 l 到 r 之間的石子合並成 k 堆。
顯然是k == 1 時,合並才是需要花費代價的。k >= 2時轉移的時候不需要加代價。
這個我當時非常不理解。然後後來想想確實是這樣的。因為k >= 2的狀態必然是由 k == 1的時候轉移過來的。
就是說將[l, r]分成k堆,必然要有幾堆合並成一堆。
同理,合並區間長度限制的時候也只在k == 1的時候考慮就好了。
轉移的時候分開按情況轉移就好了。
記憶化搜索的形式老是TLE。我也不知道為啥。。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn = 100 + 10; const int INF = 0x3f3f3f3f; int n, L, R; int dp[maxn][maxn][maxn]; int sum[maxn], a[maxn]; //int DP(int l, int r, int k)//{ // if (k > r-l+1) return INF; // if (k == r-l+1) return dp[l][r][k] = 0; // if (dp[l][r][k] != INF) return dp[l][r][k]; // // if (k == 1) // { // for (int j = L; j <= R; j++) // for (int i = l; i <= r-1; i++) // dp[l][r][k] = min(dp[l][r][k], DP(l, i, j-1)+DP(i+1, r, 1)+sum[r]-sum[l-1]);// } // else // for (int i = l; i <= r-1; i++) // dp[l][r][k] = min(dp[l][r][k], DP(l, i, k-1)+DP(i+1, r, 1)); // // return dp[l][r][k]; //} int main() { while(~scanf("%d%d%d", &n, &L, &R)) { for (int i = 1; i <= n; i++) scanf("%d", &a[i]), sum[i] = sum[i-1]+a[i]; memset(dp, INF, sizeof(dp)); //printf("%d %d\n", dp[1][1][1], 0x3f3f3f3f); 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 l = 1; l+len-1 <= n; l++) { int r = l+len-1; for (int j = 2; j <= len; j++) for (int k = l; k <= r-1; k++) dp[l][r][j] = min(dp[l][r][j], dp[l][k][j-1]+dp[k+1][r][1]); for (int j = L; j <= R; j++) for (int k = l; k <= r-1; k++) dp[l][r][1] = min(dp[l][r][1], dp[l][k][j-1]+dp[k+1][r][1]+sum[r]-sum[l-1]); } // int ans = DP(1, n, 1); printf("%d\n", dp[1][n][1]==INF ? 0:dp[1][n][1]); } }
HihoCoder - 1636 Pangu and Stones(區間DP)