DP 动态规划简单总结

我的算法是比较水的,所以最近再各种学习。现在整理一下吧 ,这几天主要在看动态规划,实习生笔试的时候淘宝的笔试题里就有一道,当时珍视不会啊,不过还好现在回了哈哈,

不多写废话了。

 

动态规划:(dynamic programming)与分之法一样是通过组合来解决问题的。

解题步骤

1.描述最优解结构

2.递归定义最优解的值

3.按自底向上的方式计算最优解


 

4.由计算出的结果构造一个最优解

 

下面是算法导论中例子

1.我就不对书里的例子分析啦

 

现在来说下这个问题。

连续子序列最大和问题 就是这样  一个数组中有一串数字,我们求出其中连续和最长的一段 如{1,2,3,4,-2,9,2}最大值为 19

 

 

 

下面我们按照解题步骤来写这个问题

1.设数组下表从1到n,我们在k位置上(0<k<=n)如果我们k位置前的和大于等于 0;我们就在k位置的值就等于k-1和+k值,否则我们的序列就需要重新开始。

2.我们定义 数组 f[i] 用来表示到 i位置处,子序列最大值,a[i]用来表示i位置出的值

则有 :    f[i]=f[i-1]+a[i]       如果 f[i-1]>=0

               f[i]=a[i]                如果f[i-1]<0;

3,

4.

3.4步省略算法直接在最后给出

package Algorithm.DP;

public class MaxContinuousSubstring {
	int [] a;//保存传入的数组
	int n;
	int [] b;//保存最长子序列
	int start=0;//存放最长子序列的起始下标
	int maxValue;
	int maxIndex;
	
//	int [] c;//用于获得最长子序列的位置
	
	public MaxContinuousSubstring(int []a){
		this.a=a;
		n=a.length;
		b=new int[n];
	}
	public void handle(){
          b[0]=a[0];
          for(int i=1;i<a.length;i++){
        	  if(b[i-1]>=0)
        		  b[i]=b[i-1]+a[i];
        	  
        	  else
        		  b[i]=a[i];  
          }
	

	}
	//获得最大和与最大元素位置
	public void caculate(){
		int j=0;
		int max=-99999;
		for(int i=0;i<b.length;i++){
			if(b[i]>max)
				{
				max=b[i];
				j=i;
				}
		}
	maxValue=max;
	maxIndex=j;
	}
	private void print(String s){
		System.out.println(s);
	}

	public void getMaxContinuousIndex(){
		int j=0;
		for(int i=maxIndex;i>=0;i--){
			if(b[i]>=0)
				j=i;
			else
				break;
		}
	start=j;
		
	}
	public void display(){
		for(int i=0;i<b.length;i++)
			System.out.println(b[i]+" ");
		print("最大值"+maxValue+"最长子序列"+start+" "+maxIndex);
	}
	public static void main(String [] args){
		int[]a=new int[]{1,2,3,-1,-20,100,34};
		int []b= new int[]{-1,-2,3,4,5,7,9};
		int[] c=new int[]{-1,-2,-3,-4,-5,-6};
		int []d=new int[]{-5,-8,22,98,0,2};
		MaxContinuousSubstring mcs=new MaxContinuousSubstring(d);
		mcs.handle();
		mcs.caculate();
		mcs.getMaxContinuousIndex();
		mcs.display();
	}


}
结果为
-5 
-8 
22 
120 
120 
122 
最大值122最长子序列2 5
 
 
 
 
 
 
 

 这个问题的时间复杂度为 o(n)  此问题共有 o(n)个子问题,每个子问题有两种选择。所以时间复杂度是 o(n)

 

 

下面是背包问题整理

1.01背包

问题定义 有固定容量的背包  有物品i种,有重量属性 c[i],  价值属性w[i]

 

直接给出状态转移方程     f[i][v]=max{f[i-1][v],f[i-1][v-c[i]+w[i]]}

给出代码

package Algorithm.DP;
/*
 * 01 背包问题
 */

public class beibao01 {
	private int [][] f;//存储容量信息
	private int [][]b;//存储存放的物品信息
	private int size;
	private int max;
	private int []x;
	private int []a;
	private int []w;
	
	public beibao01(int max,int a[],int w[]){
		this.max=max;
		this.size=a.length+1;
		this.a=a;
		this.w=w;
		x=new int[size];
		f=new int[size][max+1];
		b=new int[size][max+1];
	}

	public  void handle(){

		for(int i=1;i<size;i++){
			for(int v=1;v<max+1;v++)
				f[i][v]=0;		
		}
	
	   
	   f=new int[size][max+1];
	
	   for(int t=0;t<size;t++)
		   f[t][0]=0;
	   for(int j=0;j<max+1;j++)
		   f[0][j]=0;
	  
	   for(int i=1;i<size;i++)
		   for(int v=1;v<max+1;v++)
		   {
			  if(v-a[i-1]<0)
			
				  f[i][v]=f[i-1][v];
						  
			  else if(f[i-1][v]>f[i-1][v-a[i-1]]+w[i-1])
			
				  f[i][v]=f[i-1][v];
							
			  else			
				  f[i][v]=f[i-1][v-a[i-1]]+w[i-1];
						  
		   }
	 
		  
		
			for(int v=1;v<max+1;v++){
				for(int i=1;i<size;i++)
				System.out.print(f[i][v]+"");
			System.out.println();
		}

		
			

	
	}
	 public void traceBack(){
			int capacity=max;
			  
			for(int i=size-1;i>0;i--){
				if(f[i][capacity]==f[i-1][capacity])
				//	System.out.println(i);
					x[i]=0;
				else
					{
		
					x[i]=1;
					System.out.println(a[i-1]+"c"+capacity);
					capacity=capacity-a[i-1];
					}
			}

	}
	public  void printPath(){
		System.out.println("选择的物品为");
		for(int i=1;i<x.length;i++){
			if(x[i]==1)
				System.out.print(i+"  ");
		}
	}


	public static void main(String [] args){
		int []a ={2,1,4,5};
		int []w={1,8,8,2};
		beibao01 beibao=new beibao01(4, a, w);
	//beibao01.traceBack();
		beibao.handle();
		beibao.traceBack();
		beibao.printPath();
		
	//	beibao01.display();
	}

}


此问题时间复杂度为 0(i*v)   时间复杂度已经不能优化了 那我们来优化空间复杂度

如下这段代码

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

    for(int j=V;i>0;j--)

         {      f[v]=max{f[j],f[j-c[i]+w[i]]                  }

 

 

 

2.

 完全背包  这个问题和前面描述差不多 只是每个元素都是可选的

有以下几种解法

基本状态转换方程

f[i][v]=max{f[i-1][v],f[i-1][v-k*c[i]+k*w[i]]}   k<=V/c[i];

 

有如下几种思路来解

1.转换为 01背包 ,元素 i 转  k<=V/c[i]个元素 ,比较容易理解  时间复杂度为  o( ∑(V/c[i]*V)

2.利|用|二|进|制|思|想|   转换 i 为  k*c[i],k*w[i], k满足  2*k<=V;    这样利用二进制思想可以把时间复杂度转化为 o(∑(log(V/c[i])*V) 

3 O(p*v) 

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

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

         {      f[v]=max{f[j],f[j-c[i]+w[i]]                  }

注意与第一题的对比   ,这里我们可以做一个优化,就是把 所有 重量大并且价值少的给优化掉。 

 

 

3.下面是多重背包问题  多重背包是 第一个 与第二个问题的组合 ,也就是说元素不可以随便拿了他们有自己的上线 n[i]

状态转换方程

f[i][v]=max{f[i-1][v],f[i-1][v-k*c[i]+k*w[i]]}   0<=k<=n[i]];

 

解法:

1.转换成 01 背包

2.利用二进制思想 

把一个物品拆分成 n 个带有 系数的物品 每个物品 与价值分别为 系数乘以他们

系数分别为 1,2,4,n-1,n[i]-2^k+1;k满足n[i]-2^k+1>0的最大值

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值