动态规划学习日记(四)

12nn+1
10sum[1] [2]线、环形排列答案位置
20环形答案位置
30
40
n
123n-1nn+1n+2
a[1]a[1]+a[2]a[1]+a[2]+a[3]∑a[1 : n-1]∑a[1 : n]a[1]
∑a[1 : n-1]∑a[1 : n]a[1]+∑a[i : n-1]

例5:石子合并问题**(例题)

问题描述: 在一个圆形操场的四周摆放着n堆石子. 现在要将石子有次序地合并成一堆. 规定每次只能选相邻的2堆石子合并成一堆, 并将新的一堆石子数记为该次合并的得分. 试设计一个算法, 计算出将n堆石子合并成一堆的最小得分和最大得分.

一、确定状态:

终点:

子问题:设f[i] [j]为从i到j最小得分,g[i] [j]为从i到j最大得分;

二、确定转移方程:

f[i] [j] = min{f[i] [k] , f[k+1] [j]} + sum[i] [j]

g[i] [j] = max{f[i] [k] , f[k+1] [j]} + sum[i] [j]

三、确定初始条件和边界情况:

初始条件:f[0] [0] = g[0] [0] = 0;

边界情况:f[i] [i+1] = g[i] [i+1] = sum[i] [i+1]

四、确定计算顺序:

从小到大,填表斜行

代码:

#include<iostream>  
#include<algorithm>  
using namespace std;  
int f[205][205];  
int g[205][205];  
int a[205];  
int main()  
{  
    int i, j, k;  
    int tmp, MAX, MIN;  
    int n;  
    cin >> n;  
    for (i = 1; i <= n; i++)  
        {  
            cin >> tmp;  
            a[i] = a[i - 1] + tmp;  
            a[i + n] = tmp;  
        }  
    for (i = n + 1; i <= 2 * n; i++)  
            a[i] += a[i - 1];  
  
    for (k = 1; k <= n - 1; k++)  
        for (i = 1; i <= 2 * n - k; i++)  
            {  
                  
                MIN = 0x3f3f3f;  
                MAX = 0;  
                for (j = i + 1; j <= i + k; j++)  
                {  
                    tmp = a[i + k] - a[i - 1] + f[i][j - 1] + f[j][i + k];  
                    MAX = max(tmp,MAX);  
                    tmp = a[i + k] - a[i - 1] + g[i][j - 1] + g[j][i + k];  
                    MIN = min(tmp, MIN);  
                }  
                f[i][i + k] = MAX;  
                g[i][i + k] = MIN;  
            }  
  
        MAX = 0;  
        MIN = 0x3f3f3f;  
        for (i = 1; i <= n; i++)  
        {  
            if (f[i][i + n - 1] > MAX)  
                MAX = f[i][i + n - 1];  
            if (g[i][i + n - 1] < MIN)  
                MIN = g[i][i + n - 1];  
        }  
  
        cout << MIN << endl;  
        cout << MAX << endl;  
      
}  

总结

这道oj的题花了我很长时间,原因是没有看到题目中圆形二字,一直以为是直线排列,导致结果一直不符合测例结果又想不出原因,而进一步来说圆形意味着首尾相连,只需要在原基础上在n后复制n之前的数据即可,另外最后输出结果要注意因为是环形排列最值位置不再是f[1] [n]位置,而是会出现在f[1] [n] ~ f[n] [2n-1]位置,需要简单遍历判断 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值