【区间dp*2】洛谷 P1880 [NOI1995]石子合并 (推导过程) +尼克的任务(还没写)

版权声明:版权所有……啊重点是我简直找不到第二个人写比我还多的吐槽-。- https://blog.csdn.net/StrongerIrene/article/details/84726222

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任务+每天做了计划,就打卡。)

===========尼克的任务===========

猜你喜欢

转载自blog.csdn.net/StrongerIrene/article/details/84726222