每日算法-动态规划:程序设计实践5

简介:UPC程序设计实践课程精选算法题讲解附代码

每个专题只需要认真撰写3-5题的解题报告即可,带有视频的例题的不需要写解题报告。

【题目编号】

       动态规划1

【题目大意】

    给定一个数字三角形,每个组成部分都有一个整型的数字,求从顶端按照左下或者右下的规则,走到底端最后一行时,走过路径的数字和最大累积是多少。

【解题思路】

    经分析,从顶端往下走的时候,每个数字都对应有两种下一步的走法,从前面所学的暴力法、列举法理论上都能够解出,但是时间复杂度为O(n^n)即任意的n个数字便有2^n,显然不行;为减少计算时间,可以先使用递归函数对每一种可能的情况进行计算,但是计算结果必须存下来,留给后面需要再次计算的时候可以直接取用;把时间复杂度O(2^n)转变为空间复杂度O(n^2),当n取200时内存只耗4M不到(题目给的只有99个,索性给它定义到200去),但相对于与124M是可接受的。

【参考代码】

#include <iostream>

#include <cmath>

#define yy 110

using namespace std;

int a[yy][yy];//存每一个输入的数字

int maxsum[yy][yy];//存每个数字对于的底层求和

int n;



int getmaxs(int i,int j)

{

    if(maxsum[i][j]!=-1)//表示已经被计算过的,直接返回前面算出来了的

    {

        return maxsum[i][j];

    }

    if(i==n)//到底了

    {

        return a[i][j];

    }

    else//对应既不到底又没被算过的,需要进行计算

    {

        int x = getmaxs(i+1,j);//坐下角的

        int y = getmaxs(i+1,j+1);//右下角的

        maxsum[i][j]=max(x,y)+a[i][j];//取最大的

    }

    return maxsum[i][j];



}

int main()

{



    cin>>n;

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

    {

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

        {

            cin>>a[i][j];

            maxsum[i][j]=-1;

        }

    }

    cout<<getmaxs(1,1)<<endl;

    return 0;

}



}

题目编号

     动态规划 2

题目大意

        输入给定的序列,序列是任意的但元素之间是可以比较大小,称连续具有后一项比前一项大的序列为其上升的子列,则求出输入序列的最大升序的子序列的元素数,即这样的序列最大有几位的。

【解题思路】

    由于这样的序列是具有连续性的,所以使用循环是在所难免的;我们可以通过对每个元素逐一地进行比较,如果固定元素的前面有比它小的,我们的目标值就加一,如果遇到比他大的,先保留中间值再对比较的元素经行格式化,重复上一步的比较,最后通过比较保留的中间值进行取最大值就是我们需要的答案;第一次循环我们是对序列进行列举逐一进行,第二次就是在开头开始进行直到第一次循环的元素即为结束。

参考代码

#include <iostream>

#include <cmath>

#define maxx 1010

using namespace std;

int a[maxx];//存的是输入的元素

int maxa[maxx];//每个元素对应的最大子列数的答案数字

int flag;//中间值用

int n;

int main()

{

    cin>>n;

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

    {

        cin>>a[i];

    }

    maxa[1]=1;



    for(int i=2;i<=n;i++)//直接从第二项开始,因为已经定义了第一项(第一位对应的是1了)

    {

        flag=0;//每跑一次,就对前面的中间值进行归零

        for(int j=1; j<i;j++)//每个数前面都对应的子项数(逐一过)

        {

            if(a[j]<a[i]&&flag<maxa[j])//后一项比前一项大,而且出现新的最大值

            {

                flag=maxa[j];

            }

        }

        maxa[i]=flag+1;//点睛之笔

    }

    flag=0;

    for(int i=1;i<=n;i++)//找每个元素对应的答案的最大值就是本题的最大值

    {

        if(maxa[i]>flag)

        {

            flag=maxa[i];

        }

    }

    cout<<flag<<endl;

    return 0;

}

题目编号

    动态规则 4

题目大意

    糟了!是背包问题!没错,给定一个容积有限的背包,让我们去装最有价值的物品,给定多种物品的体积和对应的价值,每种物品只有一件,你可以取或者不娶也行;但最后的结果需要背包里的价值最大,问你怎么娶嘛?

解题思路

    首先!我想到的是这和最优解类似,只不过就是这时候变成了不可分割的了,稍微把条件改一下就行了,所以我的第一个代码是这样的:

#include <iostream>

#include <algorithm>

#include <cmath>

#define maxx 10000000

using namespace std;

struct WP//定义一个结构体存输入的物品信息

{

    int w;//重量、体积

    int v;//价值

    double xjb;//性价比,这个很重要!!!

};

WP wps[maxx];//每种物品对应的数组

int n,m;

int sum1;//存放入背包中的物品重量;

int sum2;//背包装下的价值

bool cmp(WP x,WP y)//定于一个降序的排序方法

{

    return x.xjb > y.xjb;//是基于性价比的

}

int main()

{

    cin>>n >>m;

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

    {

        cin>>wps[i].w >>wps[i].v;//输入体积、价值

        wps[i].xjb=wps[i].v*1.0/wps[i].w;//每种对应的性价比

    }

    sort(wps,wps+n,cmp);//排好序

    sum1=0;

    sum2=0;

    for(int i=0;i<n;i++)//每种都过一遍,复杂度为O(n)

    {

        if(wps[i].w+sum1<=m)//如果背包放的下这个物品

        {

            sum2+=wps[i].v;//价值就加上它

            sum1+=wps[i].w;//背包的承重量也加上它

        }

        if(sum1==m)//背包已经满了就结束

        {

            break;

        }

    }

    cout<<sum2<<endl;//输出最后背包装下的价值

    return 0;

}

结果····就离天大谱了!!!第一个测试数据过了,按此推理,应该是99.9999%都过了的,为此我还把空间上限改为10^8,没想到还是没能通过!!!我喝了口陈年红茶后细细想了想,怎么娶嘛?我啷个知道!~~这个问题放在动态规划上那是有原因的,绝对不止是最优解那么简单,接着我又喝了一口,突然想起来那个叫什么“状态”的!!!对的,我第一个代码只使用了最优解法,这算的是最优子算法而已,这样子是娶不到想要滴,还差一个状态没考虑到,那就是无后效性!!!只要每一步都是最优解,前提还得是后面的和前面的没有半毛钱关系!然后定于前面的为状态值,后面的按照最优的取,那问题不就解决了么???

参考代码

#include <iostream>

#include <algorithm>

#include <cmath>

#define maxx 1000000

using namespace std;



struct WP//定义一个结构体存输入的物品信息

{

    int w;//重量、体积

    int d;//价值

};

int f[maxx];

WP wps[maxx];//每种物品对应的数组

int n,m;

int main()

{

    cin>>n >>m;

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

    {

        cin>>wps[i].w >>wps[i].d;//输入体积、价值

    }

    for(int i=0;i<m;++i)//每种都过一遍,复杂度为O(n)

    {

        if(wps[1].w<=i)//如果背包放的下这个物品

        {

            f[i]=wps[1].d;

        }

        else

        {

            f[i]=0;

        }

    }

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

    {

        for(int j=m;j>=0;--j)

        {

            if(wps[i].w<=j)

            {

                f[j]=max(f[j],f[j-wps[i].w]+wps[i].d);

            }

        }

    }

    cout<<f[m]<<endl;//输出最后背包装下的价值

    return 0;

}

写在最后

以上代码仅供同学们参考,切勿复制粘贴、草草了事,东西是给自己学的、对自己负责;希望同学们上课时候认真听讲、做到举一反三。

如有雷同纯属巧合、若有侵权请及时联系删文

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云边牧风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值