NYOJ 737 (石子合并)

该题是一道DP题,核心思想如下:

某个区间一定是这个区间内的某两个子区间合成的(这两个子区间互补,即这两个区间加起来等于大区间),

所以我们枚举所有的情况,取个最大值即可。因为最初是从2堆石子开始无法选择,到数量大了就可以择优,体现出DP的优势。

DP[ i ] [ j ]表示 i 到 j 区间的最优合并值。

则由上述思想转移方程如下:

dp[ i ][ j ] = min(  dp[ i ][ j ], dp[ i ][ k ] + dp[k + 1][ j ] + sum[ i ][ j ] ) (i <= k <= j - 1)。

#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
int n, s[205][205], a[205], f[205][205];

int main()
{
    while(scanf("%d", &n) != EOF)
    {
        memset(s, 0, sizeof s );
        memset(a, 0, sizeof a );
        memset(f, 0, sizeof f );
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        for(int i = 1; i <= n; i++)
        {
            for(int j = i; j <= n; j++)
            {
                f[i][j] = 0x3f3f3f3f;//初值赋无限大 
                for(int k = i; k <= j; k++)
                    s[i][j] = s[i][j] + a[k];
            }
        }
        for(int i = 1; i <= n; i++)
            f[i][i] = 0;//自身初值为0 
        for(int i = 1; i < n; i++)
        {
            for(int j = 1; j <= n-i; j++)
            {
                for(int k = j; k <= i + j - 1; k++)
                {
                    if(f[j][i+j] > f[j][k] + f[k+1][i+j]+s[j][i+j])
                        f[j][i+j] = f[j][k] + f[k+1][i+j]+s[j][i+j];
                }
                printf("f[%d][%d] = %d\n", j, i+j, f[j][i+j]); 
            }
        }
        printf("%d\n", f[1][n]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fantastic123/p/8972831.html
今日推荐