中科院卜东波算法课第三题作业(dp)oj总结

(开篇必读,我是个菜鸡,所以思考的问题都是属于比较低端的,大佬请直接关闭此页)

说在之前我真的菜,乃至于明显很简单的两道题我写了15个小时左右,我是真的菜,而且我现在很生自己的气。正常人自己手打代码估计是20分钟+20分钟,一个小时就能搞定。为什么花这么久的时间,因为我“探索”了很久,现将问题总结,并期待下一次不要遇到相同的问题。(下面两)

1、lcs最大公共子序列

卜老师介绍了一种算法

我没有拿正常打dp表的方式来做这道题,而采取了老师讲述的那种方法,这就是噩梦的来源。 

1、伪代码第二行的理解:

  1. matches(k+1)=(m+1,n+1)

    有k个匹配为什么要搞一个k+1,于是我写代码的时候华丽的忽视了这一句,导致错误。我们需要注意到,matches的添加方式和之后的读取方式,对!一行一行顺序读取,那么我们假设越到最后opt越大(由于每一次都取之前表里的最大值)肯定是递增的,那么最后输出的结果就是opt[l1][l2]。假如bdad和abd那么最后一对是处在3的a和处在1的a,那么最后一个得到的opt的值是1。所以要加一个k+1行的,即统计上面所有的最大值,最后输出的时候k-1即可。

    for(int i = 0;i < l1; i++){
        for(int j = 0;j < l2; j++){
            if (S[i] == T[j]){
                matches[matches_index] = make_pair(i,j);
                matches_index++;
            }
        }
    }
    for(int k = 0; k<= matches_index; k++){
        int i = matches[k].first;  
        int j = matches[k].second;
        opt[k] = 1;
        if (k >= 1){
            for(int l = 0; l < k; l++){
                //找到当前字符对 之前的所有字符对 中 opt值最大的一个值 进行+1操作
                int i_ = matches[l].first;  
                int j_ = matches[l].second; 
                if (i_<i && j_<j){
                    opt[k] = max(opt[k],opt[l]+1);
                } 
            }
        }

    }

2、STL和pair的运用,struct和class不太熟悉,make_pair()什么的都要熟悉,在尝试使用什么表达方式的时候纠结了很久,其实我觉得!!!写算法题,没有必要这么纠结,因小失大,重点是算法思想,而不是一些很虚虚的东西。

3、日常关于ijk的起点和终点的巨大怀疑和纠结,啊,应该是和理解有很大的关系。

4、提交上去,70%的样例全部runtime error。太苦了。感谢我的尼老师(在自己有一堆作业的情况下还帮我看了代码分析了算法),在他帮助下,我认识到了我代码的不足和算法的性能和改进方法。

  • 定义数组的时候这不是一个好习惯
        int l1,l2;
        cin>>l1>>l2;
        char S[l1],T[l2];
  • Const int MAX_N = 1000改成1005 防止越过边界
  • 开1000^1000的数组最好开成全局数组

5、同时也在尼老师的帮助下我们开始分析这个算法,

它这个算法时间是有问题的,你考虑一下。假如是aaa和aaa,匹配的matches是9,对吧?也就是l^2。然后代码22行要遍历 l^2,然后第27行又需要一个 l^2,这就是 l^4的复杂度了。。

我看了看他课件,好像就是把所有的matching points找出来了。这样的话肯定会超时

所以最耽误时间的两步是建立matches表和查找每一步的matches[i]的之前的matches里最大的值

我提出了

新开一张表记录一下所有ij点之前最大的i_ j_是多少

后来发现不用新开表,就在原来的opt表上

s[i]==t[j],就左边或上边的值+1  -----> s[i]==t[j],就左上方的值+1 

所以!!!!问题来了!!

改进这个算法 兜了一圈 回到了dp最原始的做法!哈哈哈哈

2、多维01背包

就是背包除了体积和价值还有重量,好吧我上来就被吓懵了。还在网上找了很久算法,找不到我还找朋友吐槽来着。其实就是多加一个维度而已,真的是而已,太简单了实际上。就是多加了一个维度,什么都没改。

dp[j][k] = max(dp[j][k],dp[j - disk_spaces[i]][k - memorys[i]] + users[i]);

遇到的问题是:

1、被吓懵了,对。

2、又是关于该死的ijk问题啊啊啊啊,jk不需要减1,是几就是几,于是引发了一个问题,什么是从0开始,什么是从1。序号这种应该是从0开始,但是像如果那个下角标就代替一个实际的数的话,从0开始就是很傻的行为。所以这里i从0,jk从1开始。

3、i是序号从底层开始算,从0往上。但是jk是从大往小里写【有趣的是,我在写这一篇博客的时候突然开始想为什么原来只有体积的时候都可以从小往上写,现在多维就不行了,哈哈哈哈,还有我就思考出了一个重大发现】【这里先留个彩蛋问题,之后揭晓,这其实还有个优化存在】

4、鼓起勇气过oj了,结果全是runtime error和这个肝上了好生气。因为这些取值都是1000,也就是说我的opt数组得开1000*1000*1000。根本过不去。

5、感谢我的刁爸爸给我提供了代码,我研究得知一种降维度的办法,就是共享二维的表格,而不是开三维数组,直接节省了1000倍的空间。也就是说直接把i去掉。【彩蛋答案】因为共享了二维表,相当于算第i层的时候需要取第i-1层的数据的时候,不是多开一维由原来在空间里的开辟的第i层数据来表示,而是放在二维表里。如果ij是从0开始往大写,则算jk时候更新二维表的时候会覆盖原有i-1层得出的值的表格,导致用的数据是第i层新算出的,而不是原来i-1层保留的数据。如果倒着算,倒着填表,使用之前的数据就是第i-1层的

 

整个思路就是这样的。感谢在oj路上帮助我的朋友们。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值