emmmmm给自己设置了一个习惯界限。其实每次看到他们在做啥啥啥而我都大三都现在了 就会感觉很内伤-、-
不过算法还是要写的吧 别写太多而已...
为了防止脑袋空空 也为了防止一天不知道干什么
==================================
石子合并:
经典 的区间dp题目
===============
然后呢,基本其实也就两种模型-----括号一种,石子一种……
之前的括号合并+石子以前写过:https://blog.csdn.net/StrongerIrene/article/details/81944120?utm_source=blogxgwz7
但是我的版本并不能轻易让人看懂,所以还是去看了紫书的dp部分。
总结一下就是:(基于紫书的讲解来)
题目是给木棍,3个可以切的位置,10米长,2 4 7 每次切到的花费是你当前切的木棍的长度 问怎么切会使得切得费用最少?
(按照2 4 7 就是10+ (8left) 8+(6left)6+
4 2 7 则是 10+(6 4 left)4+ (2 2 6 left) 6+ (2 2 3 3left) )
下面的4 2 7 是更好的。我们前面还记得动态规划的时候,有一个特点是。任何地方停下来都是最好的
而另一个题目是,石子合并,代价是石子的块数(数目)(NOI1995 在落谷上面)
可是呢?
就石子而言,可以得到,最后一次的肯定是最好的,那前面呢?最后石子的和是22,22可以是由 18+4 4+18 9+13得来的。(当时其实想到了,但是不确定哪个方向来的最好-------------与其不知道,复杂度也够了的情况下,不如这个方向检验一下,这样就得到了我们的区间dp策略。
那么再回到小木棍。
这个状态怎么说呢,有一点带权值的感觉。所得到的值是和分片划分又糅合起来的感觉一样的。。每个状态里搞出来的不仅仅是dp(i,j)...相加,还有此次运算搞出来的东西,找找专业说法是什么。。
区间DP主要是把一个大区间拆分成几个小区间,先求小区间的最优值,然后合并起来求大区间的最优值。
区间DP最关键的就是满足最优子结构以及无后效性!!!
对于这个洛谷题目我还是尝试下写一写吧。毕竟属于复习的内容。。。。(不知道自己现在学算法为了什么。。。PAT+CCF明明就不一样吧-。-)啊,为了看上去还没那么菜,要变强还要学这个流那个流什么的一堆东西。。。 还有就是自己喜欢,刷完洛谷100题起码不会和没搞过的人完全一样吧。
最后A了!!!!!!!!!!!
在孜杰的鞭笞帮助下
发现了,我很容易写一些小错误~
比如minn maxx什么的
另外还有,对于两个差不多的(我的就是dp1和dp2 改了不同步的地方最好直接复制~因为不同步,往往只是改了一边儿。或者不用复制,直接写在一个dp(。。。)里面。)
小错误不断:比如区间最大值
这个范围,不能越界,也不能漏掉!
拿2--4来说:
2/2 3 /4
2/3 4/4 这个呢 范围也就是
(按照代码来: )t=dp(.....) ←这个i是x到y-1的
(按照代码来: )t=dp(,...)← 这个i+1是x+1到y的 (所以,最开始写i<=y 那么Y+1到y会错啊
因为是分成两块组成的嘛。不能等于y否则下面就dp(5,4)什么的了。总之多写吧emmmm
(但是其实可以自己事先觉察到的)
//我不知道她的话是不是带有鄙视成分 我亦不知道我能做成什么样子
//总之日常保持算法洛谷的能力总归没错!!!!
//不然搞其他都是虚的!!可不要小看系主任!!!!
#include <bits/stdc++.h>
using namespace std;
int n;
int a[205];
int d[205][205];
int d2[205][205];
int cal(int i,int j){
int sum=0;
for(int k=i;k<=j;k++){
sum+=a[k];
}
return sum;
}
int dp(int x, int y){
int maxx=0;
if(x==y)return 0;//!!!!hope this never appear!!!!
if(y-x==1)return (a[x]+a[y]);
if(d[x][y]!=0)return d[x][y];
int t=0;
int sum=cal(x,y);
//x==1 y==2
//i=2 i<2 never comes into
//y=3 comes once
for(int i=x;i<y;i++){
t=dp(x,i);
t+=dp(i+1,y);
maxx=max(t,maxx);
}
maxx+=sum;
d[x][y]=maxx;
//printf(" x is %d y is %d maxx is %d \n",x,y,maxx);
return maxx;
}
int dp2(int x, int y){
int maxx=999999999;
if(x==y)return 0;//!!!!hope this never appear!!!!
if(y-x==1)return (a[x]+a[y]);
if(d2[x][y]!=0)return d2[x][y];
int t=0;
int sum=cal(x,y);
for(int i=x;i<y;i++){
t=dp2(x,i);
t+=dp2(i+1,y);
maxx=min(t,maxx);
}
maxx+=sum;
d2[x][y]=maxx;
//printf(" x is %d y is %d maxx is %d \n",x,y,maxx);
return maxx;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i+n]=a[i];
}
dp(1,n);
//一共有n+1种方法
//i=0 1--n
//i=n 1+n--2*n
int maxxx=-1;
for(int i=0;i<=n;i++){
maxxx=max(maxxx,dp(1+i,n+i));
}
int minnn=999999999;
for(int i=0;i<=n;i++){
minnn=min(minnn,dp2(1+i,n+i));
}
cout<<minnn<<endl;
cout<<maxxx<<endl;
return 0;
}
另外,之前一道“会坏掉的项链”题目中,如果对于环形。。。。 我们有一个解决方案,那就是区间加长一倍。其中只要控制一下区间长度就好了(不超过xxx)对于这个题就是dp多写一点。。
@四边形不等式算法优化了一维。使得它从三次方降级到了平方(先别管。。)
@刚才看了一个人的博客。。。。
哎 总不能不学习 哪怕你说什么借口不喜欢啊不想啊
按照番茄todo上的计划每天一步一步来吧。
(小日常app上,每天完成todo任务+每天做了计划,就打卡。)
===========尼克的任务===========