动态规划 线性模型 Leetcode.300 POJ3486

 线性指的是状态的排布是线性的,最长单调上升子序列为经典的线性模型

leetcode300:最长递增子序列

用f[i]表示以a[i]结尾的最长上升子序列问题

计算f[i]的时候,只需要考虑f[1],f[2],...,f[i-1]是否能够转移

状态转移方程:f[i]=max{f[j]+1|1<=j<i,a[i]<a[j]} ,并将此集合称为决策允许集合,我们只能从允许的j里找f[j]+1来更新f[i].

代码:

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int len=nums.size();
        int f[len];
        for(int i=0;i<len;i++)
        f[i]=1;
        int maxlen=1;
        for(int i=1;i<len;i++)
        for(int j=0;j<=i-1;j++)
        {
            if(nums[i]>nums[j])
            f[i]=max(f[i],f[j]+1);
            maxlen=maxlen<f[i]?f[i]:maxlen;
        }
    return maxlen;
    }
};

poj3086

题目大意:

想保证n年里都有一台电脑,一开始你有n台,如果在第y年购买了一台电脑,那么你需要花费c的代价。

如果那台电脑一直用到了第z年,在第z年又买了一台新的,你需要支付m(y,z)的维修费用

给定n,c,数组m。求最小花费。 

m(x年开始买入,用到了y年年末)

题解:我们将每年划分为一个阶段

f[i]表示直到第i年都有一台电脑的最小花费。

f[i]需要从f[0],f[1],...,f[i-1]转移过来。

对于第i年的最小花费,我们依次设置变量从1到i依次枚举上次买电脑是哪一年。

假设上次买电脑是第j年,那么1~j-1年就是一个子问题,我们已经求出了f[j-1]是满足此问题的最优解,后面就不用考虑前j-1年的情况,且它也不会影响我们对后面的决策。

第j年到第i年的维修费用是m(j,i),花费为c

因此可以用f[j-1]+m(j,i)+c来更新f[i]

f[i]=min{f[i],f[j-1]+m(j,i)+c}     (1<=j<=i)

代码实现:

memset(f,0x3f,sizeof(f));

f[0]=0;

for(int i=1;i<=n;i++)

        for(int j=1;j<=i;j++)

                f[i]=min{f[i],f[j-1]+m[j][i]+c};

printf("%d\n",f[n]);

时间复杂度O(n^2)

为了增加对无后效性的理解,我们以本题的数据为例,给出每次枚举过程:

一:
i=1,j=1:f[1]=min(f[1],f[0]+m(1,1)+c)=8
二:
i=2,j=1:f[2]=min(f[2],f[0]+m(1,2)+c)=3+7=10
i=2,j=2:f[2]=min(f[2],f[1]+m(2,2)+c)=min(10,8+6+3)=10

三:
i=3,j=1:f[3]=min(f[3],f[0]+m(1,3)+c)=50+3=53
i=3,j=2:f[3]=min(f[3],f[1]+m(2,3)+c)=min(53,8+8+3)=19
i=3,j=3:f[3]=min(f[3],f[2]+m(3,3)+c)=min(19,10+10+3)=19

可以看到在i=3循环内,每次枚举所用到的f[1],f[2],都是之前求出的最优解,直接用就可以。

至于为什么min里面要用f[j-1],是因为对于f[i]=min{f[i],f[j-1]+m[j][i]+c}为i年的最小花费,

若上次买电脑的年份为第j年,那么第(j~i)年的费用总和为第j年买电脑的费用c加上之后的维修费

m(j,i),只需要加上前j-1年的总花费就可以了。
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值