您的位置:首页 > 其它

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

2014-06-14 21:19 253 查看
在一个操场上摆放着一行共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 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划