nyoj 737 石子合并(一)。区间dp
2016-12-27 00:13
495 查看
http://acm.nyist.net/JudgeOnline/problem.php?pid=737
数据很小,适合区间dp的入门
对于第[i, j]堆,无论你怎么合并,无论你先选哪两堆结合,当你把[i, j]合成一堆的那一步的时候,花费肯定就是sum[i....j]
可以用纸模拟下。
那么我们设dp[i][j]表示把i...j堆合成一堆的时候的最小花费。
比如dp[1][1] = 0。dp[1][2] = a[1] + a[2];
那么要求dp[i][j],则可以是dp[i][k] + dp[k + 1][j] + cost
注意dp的时候的顺序,因为要求dp[1]
,则需要用到dp[1][k]和dp[k]
你需要考虑下怎么for,才能使得子问题已经被算出,建议一开始用dfs + 记忆化做。
这里dp的顺序应该是先算出2个集合的,3个、4个、......
就是先算出dp[1][2], dp[2][3],这使得求dp[1][3]成为可能。
all dp[i][i] = 0
View Code
简单来说,就是设s[i][j]表示第i---j堆石子合并的时候,在第s[i][j]那里合并,是最优的。
那么可以证明的是:s[i][j - 1] <= s[i][j] <= s[i + 1][j]
那么只需要枚举里面的值就好了。
数据很小,适合区间dp的入门
对于第[i, j]堆,无论你怎么合并,无论你先选哪两堆结合,当你把[i, j]合成一堆的那一步的时候,花费肯定就是sum[i....j]
可以用纸模拟下。
那么我们设dp[i][j]表示把i...j堆合成一堆的时候的最小花费。
比如dp[1][1] = 0。dp[1][2] = a[1] + a[2];
那么要求dp[i][j],则可以是dp[i][k] + dp[k + 1][j] + cost
注意dp的时候的顺序,因为要求dp[1]
,则需要用到dp[1][k]和dp[k]
你需要考虑下怎么for,才能使得子问题已经被算出,建议一开始用dfs + 记忆化做。
这里dp的顺序应该是先算出2个集合的,3个、4个、......
就是先算出dp[1][2], dp[2][3],这使得求dp[1][3]成为可能。
all dp[i][i] = 0
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> int n; const int maxn = 1e3 + 20; int dp[maxn][maxn]; int s[maxn][maxn]; int sum[maxn]; void work() { for (int i = 1; i <= n; ++i) { int x; scanf("%d", &x); sum[i] = sum[i - 1] + x; dp[i][i] = 0; s[i][i] = i; } for (int dis = 1; dis <= n - 1; ++dis) { for (int be = 1; be + dis <= n; ++be) { int en = be + dis; dp[be][en] = inf; int t = s[be][en]; for (int k = s[be][en - 1]; k <= s[be + 1][en]; ++k) { if (k + 1 > en) break; if (dp[be][en] >= dp[be][k] + dp[k + 1][en] + sum[en] - sum[be - 1]) { dp[be][en] = dp[be][k] + dp[k + 1][en] + sum[en] - sum[be - 1]; t = k; } } s[be][en] = t; } } cout << dp[1] << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif while (scanf("%d", &n) != EOF) work(); return 0; }
View Code
简单来说,就是设s[i][j]表示第i---j堆石子合并的时候,在第s[i][j]那里合并,是最优的。
那么可以证明的是:s[i][j - 1] <= s[i][j] <= s[i + 1][j]
那么只需要枚举里面的值就好了。
相关文章推荐
- nyoj 737 石子合并(一)(区间DP)
- NYOJ737 石子合并(一)(区间dp,详细)
- NYOJ - 737 - 石子合并(一)(区间DP)
- nyoj 737 石子合并(一)(区间DP)
- nyoj 737 石子合并(一)(区间DP)
- nyoj 737 石子合并(一)(区间DP)
- nyoj 737 石子合并(一) 【区间dp】
- NYOJ题目737石子合并(一)(区间dp)
- nyoj 737 石子合并(一)(区间DP)
- Nyoj 737: 石子合并(一)(区间DP+四边形优化)
- nyoj 737 石子合并(一)(区间DP)
- NYOJ 737 石子合并(一)(区间dp)
- nyoj737石子合并【区间dp】
- nyoj 737 石子合并(一)(区间DP)
- 区间DP-NYOJ737石子合并
- 【区间DP】NYOJ 737石子合并+POJ 2955 Brackets(括号匹配)+NYOJ 15 括号匹配(二)
- NYOJ 737 石子合并(一)(区间dp)
- nyoj737石子合并(一)【区间dp】
- nyoj 737 石子合并(一)(区间DP)
- nyoj 737 石子合并(一)(区间DP)