石子合并问题(动态规划)
2014-06-14 21:19
253 查看
在一个操场上摆放着一行共n堆的石子。现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆石子数记为该次合并的得分。请编辑计算出将n堆石子合并成一堆的最小得分和将n堆石子合并成一堆的最大得分。
容易想到贪心法,但可惜是错误的。
需要用到动态规划,类似于矩阵链乘。
--------------------------
环形的:将环变成2*n的线型
平行四边形法则优化:
容易想到贪心法,但可惜是错误的。
需要用到动态规划,类似于矩阵链乘。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAX_N = 101; const int INF = 0x3f3f3f3f; int n; int a[MAX_N]; int d[MAX_N][MAX_N]; int sum[MAX_N]; void solve() { //init sum[] sum[0] = a[0]; for ( int i = 1; i < n; i++ ) { sum[i] = sum[i - 1] + a[i]; } //init dp for ( int i = 0; i < n; i++ ) { for ( int j = 0; j < n; j++ ) { if ( i == j ) { d[i][j] = 0; } else { d[i][j] = -INF; } } } //dp for ( int v = 1; v < n; v++ ) { for ( int i = 0; i < n - v; i++ ) { int j = i + v; int s = sum[j] - ( i > 0 ? sum[i-1] : 0 ); for ( int k = i; k < j; k++ ) { d[i][j] = max ( d[i][j], d[i][k] + d[k + 1][j] + s ); } } } printf ( "%d\n", d[0][n - 1] ); } int main() { freopen ( "in.txt", "r", stdin ); scanf ( "%d", &n ); for ( int i = 0; i < n; i++ ) { scanf ( "%d", a + i ); } solve(); return 0; }
--------------------------
环形的:将环变成2*n的线型
#include <iostream> #include <cstdio> using namespace std; const int MAX_N = 101, INF = 0x3f3f3f3f; int n; bool isLoop = false; int a[MAX_N*2]; int sum[MAX_N*2]; int d[MAX_N*2][MAX_N*2]; void solve() { //init sum array for ( int i = 0; i < 2 * n; i++ ) { if ( i == 0 ) { sum[0] = a[0]; } else { sum[i] = sum[i - 1] + a[i]; } } //init dp array for ( int i = 0; i < 2 * n; i++ ) { for ( int j = 0; j < 2 * n; j++ ) { if ( i == j ) { d[i][j] = 0; } else { d[i][j] = -INF; } } } for ( int v = 1; v < n; v++ ) { for ( int i = 0; i < 2 * n - v; i++ ) { int j = i + v; int s = sum[j] - ( i > 0 ? sum[i - 1] : 0 ); for ( int k = i; k < j; k++ ) { d[i][j] = max ( d[i][j], d[i][k] + d[k + 1][j] + s ); } } } int ans = -INF; for ( int i = 0; i < n + 1; i++ ) { ans = max ( ans, d[i][n - 1 + i ] ); } printf ( "%d\n", ans ); } int main() { freopen ( "in.txt", "r", stdin ); while ( ~scanf ( "%d", &n ) && n ) { isLoop = true; for ( int i = 0; i < n; i++ ) { scanf ( "%d", a + i ); } if ( isLoop ) { for ( int i = n; i < 2 * n; i++ ) { a[i] = a[i - n]; } } solve(); } }
平行四边形法则优化:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAX_N = 101; const int INF = 0x3f3f3f3f; int n; int a[MAX_N]; int d[MAX_N][MAX_N]; int K[MAX_N][MAX_N]; int sum[MAX_N]; void solve() { //init sum[] sum[0] = a[0]; for ( int i = 1; i < n; i++ ) { sum[i] = sum[i - 1] + a[i]; } //init dp for ( int i = 0; i < n; i++ ) { for ( int j = 0; j < n; j++ ) { if ( i == j ) { d[i][j] = 0; K[i][j] = i; } else { d[i][j] = -INF; } } } //dp for ( int v = 1; v < n; v++ ) { for ( int i = 0; i < n - v; i++ ) { int j = i + v; int s = sum[j] - ( i > 0 ? sum[i - 1] : 0 ); //for ( int k = i; k < j; k++ ) //{ // d[i][j] = max ( d[i][j], d[i][k] + d[k + 1][j] + s ); //} int Max = -INF; for ( int k = K[i][j - 1]; k <= K[i + 1][j]; k++ ) { if ( Max < d[i][k] + d[k + 1][j] + s ) { Max = d[i][k] + d[k + 1][j] + s; K[i][j] = k; } } d[i][j] = Max; } } printf ( "%d\n", d[0][n - 1] ); } int main() { freopen ( "in.txt", "r", stdin ); scanf ( "%d", &n ); for ( int i = 0; i < n; i++ ) { scanf ( "%d", a + i ); } solve(); return 0; }
相关文章推荐
- 动态规划:石子合并问题
- 算法_动态规划_石子合并问题
- 石子合并问题(动态规划)
- 石子合并问题--动态规划;贪心
- 石子合并问题--动态规划;贪心
- poj1738 An old Stone Game 【GarsiaWachs算法】【动态规划】经典合并石子问题
- 石子合并问题 --动态规划--解法1
- 石子合并问题
- 动态规划解循环石子堆合并问题
- 石子合并问题 -- 任意版
- 石子合并问题分析(转)
- scau 9209 石子合并问题
- NK 1137 石子合并问题
- 石子合并(动态规划)详细解题报告(转)
- 【原】动态规划——石子划分问题
- 石子合并问题
- 石子合并问题
- 石子合并(动态规划)详细解题报告
- 环形石子合并问题 - 经典DP问题
- 石子合并(动态规划)详细解题报告