石子合并问题(动态规划)

来源:互联网 发布:数据库程序设计 编辑:程序博客网 时间:2024/04/30 02:00

在一个操场上摆放着一行共n堆的石子。现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆石子数记为该次合并的得分。请编辑计算出将n堆石子合并成一堆的最小得分和将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 dpfor ( 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;}}}//dpfor ( 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 arrayfor ( int i = 0; i < 2 * n; i++ ){if ( i == 0 ){sum[0] = a[0];}else{sum[i] = sum[i - 1] + a[i];}}//init dp arrayfor ( 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 dpfor ( 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;}}}//dpfor ( 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;}


0 0
原创粉丝点击