10计本算法最大矩阵和01背包问题
贪心算法-01背包问题

贪⼼算法-01背包问题1、问题描述:给定n种物品和⼀背包。
物品i的重量是wi,其价值为vi,背包的容量为C。
问:应如何选择装⼊背包的物品,使得装⼊背包中物品的总价值最⼤?形式化描述:给定c >0, wi >0, vi >0 , 1≤i≤n.要求找⼀n元向量(x1,x2,…,xn,), xi∈{0,1}, ∋ ∑ wi xi≤c,且∑ vi xi达最⼤.即⼀个特殊的整数规划问题。
2、最优性原理:设(y1,y2,…,yn)是 (3.4.1)的⼀个最优解.则(y2,…,yn)是下⾯相应⼦问题的⼀个最优解:证明:使⽤反证法。
若不然,设(z2,z3,…,zn)是上述⼦问题的⼀个最优解,⽽(y2,y3,…,yn)不是它的最优解。
显然有∑vizi > ∑viyi (i=2,…,n)且 w1y1+ ∑wizi<= c因此 v1y1+ ∑vizi (i=2,…,n) > ∑ viyi, (i=1,…,n)说明(y1,z2, z3,…,zn)是(3.4.1)0-1背包问题的⼀个更优解,导出(y1,y2,…,yn)不是背包问题的最优解,⽭盾。
3、递推关系:设所给0-1背包问题的⼦问题的最优值为m(i,j),即m(i,j)是背包容量为j,可选择物品为i,i+1,…,n时0-1背包问题的最优值。
由0-1背包问题的最优⼦结构性质,可以建⽴计算m(i,j)的递归式:注:(3.4.3)式此时背包容量为j,可选择物品为i。
此时在对xi作出决策之后,问题处于两种状态之⼀:(1)背包剩余容量是j,没产⽣任何效益;(2)剩余容量j-wi,效益值增长了vi ;使⽤递归C++代码如下:#include<iostream>using namespace std;const int N=3;const int W=50;int weights[N+1]={0,10,20,30};int values[N+1]={0,60,100,120};int V[N+1][W+1]={0};int knapsack(int i,int j){int value;if(V[i][j]<0){if(j<weights[i]){value=knapsack(i-1,j);}else{value=max(knapsack(i-1,j),values[i]+knapsack(i-1,j-weights[i]));}V[i][j]=value;}return V[i][j];}int main(){int i,j;for(i=1;i<=N;i++)for(j=1;j<=W;j++)V[i][j]=-1;cout<<knapsack(3,50)<<endl;cout<<endl;}不使⽤递归的C++代码:简单⼀点的修改//3d10-1 动态规划背包问题#include <iostream>using namespace std;const int N = 4;void Knapsack(int v[],int w[],int c,int n,int m[][10]);void Traceback(int m[][10],int w[],int c,int n,int x[]);int main(){int c=8;int v[]={0,2,1,4,3},w[]={0,1,4,2,3};//下标从1开始int x[N+1];int m[10][10];cout<<"待装物品重量分别为:"<<endl;for(int i=1; i<=N; i++){cout<<w[i]<<" ";}cout<<endl;cout<<"待装物品价值分别为:"<<endl;for(int i=1; i<=N; i++){cout<<v[i]<<" ";}cout<<endl;Knapsack(v,w,c,N,m);cout<<"背包能装的最⼤价值为:"<<m[1][c]<<endl;Traceback(m,w,c,N,x);cout<<"背包装下的物品编号为:"<<endl;for(int i=1; i<=N; i++){if(x[i]==1){cout<<i<<" ";}}cout<<endl;return 0;}void Knapsack(int v[],int w[],int c,int n,int m[][10]){int jMax = min(w[n]-1,c);//背包剩余容量上限范围[0~w[n]-1] for(int j=0; j<=jMax;j++){m[n][j]=0;}for(int j=w[n]; j<=c; j++)//限制范围[w[n]~c]{m[n][j] = v[n];}for(int i=n-1; i>1; i--){jMax = min(w[i]-1,c);for(int j=0; j<=jMax; j++)//背包不同剩余容量j<=jMax<c{m[i][j] = m[i+1][j];//没产⽣任何效益}for(int j=w[i]; j<=c; j++) //背包不同剩余容量j-wi >c{m[i][j] = max(m[i+1][j],m[i+1][j-w[i]]+v[i]);//效益值增长vi }}m[1][c] = m[2][c];if(c>=w[1]){m[1][c] = max(m[1][c],m[2][c-w[1]]+v[1]);}}//x[]数组存储对应物品0-1向量,0不装⼊背包,1表⽰装⼊背包void Traceback(int m[][10],int w[],int c,int n,int x[]){for(int i=1; i<n; i++){if(m[i][c] == m[i+1][c]){x[i]=0;}else{x[i]=1;c-=w[i];}}x[n]=(m[n][c])?1:0;}运⾏结果:算法执⾏过程对m[][]填表及Traceback回溯过程如图所⽰:从m(i,j)的递归式容易看出,算法Knapsack需要O(nc)计算时间; Traceback需O(n)计算时间;算法总体需要O(nc)计算时间。
0-1背包问题的多种解法

问题描述0/1 背包问题 :现有 n 种物品,对 1<=i<=n ,已知第 i 种物品的重量为正整数 W i ,价值为正整数 V i , 背包能承受的最大载重量为正整数 W ,现要求找出这 n 种物品的一个子集,使得子集中物 品的总重量不超过 W 且总价值尽量大。
(注意:这里对每种物品或者全取或者一点都不取, 不允许只取一部分)算法分析根据问题描述,可以将其转化为如下的约束条件和目标函数:nw i x i W i 1 i i(1)x i { 0,1}( 1 i n)nmax v i x i (2) i1于是,问题就归结为寻找一个满足约束条件( 1 ),并使目标函数式( 2 )达到最大的 解向量 X (x 1, x 2 ,x 3, ........... , x n ) 。
首先说明一下 0-1 背包问题拥有最优解。
假设 (x 1,x 2,x 3, ........ ,x n ) 是所给的问题的一个最优解, 则(x 2,x 3, ............... ,x n )是下面问题的n n n个问 题 的 一 个 最 优解 , 则v i y iv i x i , 且 w 1x 1w i y i W 。
因此 ,i 2 i 2 i 2一个最优解:w i x i Wi2w 1x 1nmax v i x i 。
如果不是的话,设(y 2,y 3, , y n ) 是这x i {0,1}( 2 i n)i2n n nv1x1 v i y i v1x1 v i x i v i x i ,这说明(x1,y2,y3, ............. ,y n) 是所给的0-1 背包问i 2 i 2 i 1题比( x1 , x 2 , x3 , ... , x n ) 更优的解,从而与假设矛盾。
穷举法:用穷举法解决0-1 背包问题,需要考虑给定n 个物品集合的所有子集,找出所有可能的子集(总重量不超过背包重量的子集) ,计算每个子集的总重量,然后在他们中找到价值最大的子集。
背包问题全类型

背包问题全类型背包问题给定⼀组物品,每种物品都有⾃⼰的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最⾼。
背包问题⼤体都可以⽤上述⽅式进⾏描述,但在具体的问题上有了不同的限制条件,于是便有了各种类型的背包问题。
背包问题可基本分为0-1背包问题、部分背包问题、多重背包问题、完全背包问题四⼤类。
接下从四种问题的解决的核⼼算法可以把部分背包问题单独化为⼀类,其核⼼算法为贪⼼。
其余的三种背包问题都可以⽤动态规划解决。
造成部分背包问题与其他的背包问题最⼤不同的原因是其限定条件的不同,部分1. 部分背包问题限定条件:每件物品可以只选取⼀部分完整问题描述:有 n 件物品,第i件物品重 w[i],价值为 v[i],且每件物品可以进⾏分割,分割后的价值按取⾛重量占该物品总重量的⽐值计算。
在不超过最⼤承载量 C 的范围内,问最⼤可以取⾛的价值为多少?( 其中 i ∈ {1,2,3,···,n} )算法:贪⼼分析:根据本题的特殊性,我们可以任意地对某⼀部品进⾏分割,所以我们优先选择性价⽐⾼的物品,即单位重量下物品的价值。
解题代码//C++#include<cstdio>#include<algorithm>#include<iostream>using namespace std;struct bag { int w,v; //w表⽰重量 v表⽰价值 double p; //⽤来储存v/w 性价⽐}a[10005];bool cmp(bag x,bag y) { return x.p > y.p; //性价⽐⾼的物品排在前⾯}int main() {剩余 } } printf('%.2f\n', ans); //输出答案 return 0;}注意计算时注意数据类型在计算“性价⽐”的时候要注意,在C/C++等⼀部分语⾔中存在以下机制 int/int = int ,这样是⽆法计算出⼩数的,需要将其中任意⼀项浮点化即可。
分支界限方法01背包问题解题步骤

分支界限方法是一种用于解决优化问题的算法。
在动态规划算法中,分支界限方法被广泛应用于解决01背包问题。
01背包问题是一个经典的动态规划问题,其解题步骤如下:1. 确定问题:首先需要明确01背包问题的具体描述,即给定一组物品和一个背包,每个物品有自己的价值和重量,要求在不超过背包容量的情况下,选取尽可能多的物品放入背包,使得背包中物品的总价值最大。
2. 列出状态转移方程:对于01背包问题,可以通过列出状态转移方程来描述问题的求解过程。
假设dp[i][j]表示在前i个物品中,背包容量为j时能够获得的最大价值,则状态转移方程可以表示为:dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]]+v[i])3. 初始化边界条件:在动态规划中,需要对状态转移方程进行初始化,一般情况下,dp数组的第一行和第一列需要单独处理。
对于01背包问题,可以初始化dp数组的第一行和第一列为0。
4. 利用分支界限方法优化:针对01背包问题,可以使用分支界限方法来优化动态规划算法的效率。
分支界限方法采用广度优先搜索的思想,在每一步选择最有希望的分支,从而减少搜索空间,提高算法的效率。
5. 实际解题步骤:根据上述步骤,实际解决01背包问题的步骤可以概括为:确定问题,列出状态转移方程,初始化边界条件,利用分支界限方法优化,最终得到问题的最优解。
分支界限方法在解决01背包问题时起到了重要的作用,通过合理的剪枝策略,可以有效地减少动态规划算法的时间复杂度,提高问题的求解效率。
分支界限方法也可以应用于其他优化问题的求解过程中,在算法设计和实现中具有重要的理论和实际意义。
在实际应用中,分支界限方法需要根据具体问题进行灵活选择和调整,结合动态规划和剪枝策略,以便更好地解决各类优化问题。
掌握分支界限方法对于解决复杂问题具有重要的意义,也是算法设计和优化的关键技术之一。
分支界限方法在解决01背包问题的过程中,具有重要的作用。
(完整版)01背包问题

01背包问题,是用来介绍动态规划算法最经典的例子,网上关于01背包问题的讲解也很多,我写这篇文章力争做到用最简单的方式,最少的公式把01背包问题讲解透彻。
01背包的状态转换方程f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }只要你能通过找规律手工填写出上面这张表就算理解了01背包的动态规划算法。
首先要明确这张表是至底向上,从左到右生成的。
为了叙述方便,用e2单元格表示e行2列的单元格,这个单元格的意义是用来表示只有物品e时,有个承重为2的背包,那么这个背包的最大价值是0,因为e物品的重量是4,背包装不了。
对于d2单元格,表示只有物品e,d时,承重为2的背包,所能装入的最大价值,仍然是0,因为物品e,d都不是这个背包能装的。
同理,c2=0,b2=3,a2=6。
对于承重为8的背包,a8=15,是怎么得出的呢?根据01背包的状态转换方程,需要考察两个值,一个是f[i-1,j],对于这个例子来说就是b8的值9,另一个是f[i-1,j-Wi]+Pi;在这里,f[i-1,j]表示我有一个承重为8的背包,当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值f[i-1,j-Wi]表示我有一个承重为6的背包(等于当前背包承重减去物品a的重量),当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值f[i-1,j-Wi]就是指单元格b6,值为9,Pi指的是a物品的价值,即6由于f[i-1,j-Wi]+Pi = 9 + 6 = 15 大于f[i-1,j] = 9,所以物品a应该放入承重为8的背包以下是actionscript3 的代码public function get01PackageAnswer(bagItems:Array,bagSize:int):Array{var bagMatrix:Array=[];var i:int;var item:PackageItem;for(i=0;i<bagItems.length;i++){bagMatrix[i] = [0];}for(i=1;i<=bagSize;i++){for(varj:int=0;j<bagItems.length;j++){item = bagItems[j] as PackageItem;if(item.weight > i){//i背包转不下itemif(j==0){bagMatrix[j][i] = 0;}else{bagMatrix[j][i]=bagMatrix[j-1][i];}}else{//将item装入背包后的价值总和var itemInBag:int;if(j==0){bagMatrix[j][i] = item.value;continue;}else{itemInBag = bagMatrix[j-1][i-item.weight]+item.value;}bagMatrix[j][i] = (bagMatrix[j-1][i] > itemInBag ? bagMatrix[j-1][i] : itemInBag)}}}//find answervar answers:Array=[];var curSize:int = bagSize;for(i=bagItems.length-1;i>=0;i--){item = bagItems[i] as PackageItem;if(curSize==0){break;}if(i==0 && curSize > 0){answers.push();break;}if(bagMatrix[i][curSize]-bagMatrix[i-1][curSize-item.weight ]==item.value){answers.push();curSize -= item.weight;}}return answers;}PackageItem类public class PackageItem{public var name:String;public var weight:int;public var value:int;public function PackageItem(name:String,weight:int,value:int){ = name;this.weight = weight;this.value = value;}}测试代码varnameArr:Array=['a','b','c','d','e'];var weightArr:Array=[2,2,6,5,4];var valueArr:Array=[6,3,5,4,6];var bagItems:Array=[];for(vari:int=0;i<nameArr.length;i++){var bagItem:PackageItem = new PackageItem(nameArr[i],weightArr[i],valueArr[i]);bagItems[i]=bagItem;}var arr:Array = ac.get01PackageAnswer(bagItems,10);。
c语言算法--贪婪算法---01背包问题

c语言算法--贪婪算法---0/1背包问题在0 / 1背包问题中,需对容量为c 的背包进行装载。
从n 个物品中选取装入背包的物品,每件物品i 的重量为wi ,价值为pi 。
对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高,即n ?i=1pi xi 取得最大值。
约束条件为n ?i =1wi xi≤c 和xi?[ 0 , 1 ] ( 1≤i≤n)。
在这个表达式中,需求出xt 的值。
xi = 1表示物品i 装入背包中,xi =0 表示物品i 不装入背包。
0 / 1背包问题是一个一般化的货箱装载问题,即每个货箱所获得的价值不同。
货箱装载问题转化为背包问题的形式为:船作为背包,货箱作为可装入背包的物品。
例1-8 在杂货店比赛中你获得了第一名,奖品是一车免费杂货。
店中有n 种不同的货物。
规则规定从每种货物中最多只能拿一件,车子的容量为c,物品i 需占用wi 的空间,价值为pi 。
你的目标是使车中装载的物品价值最大。
当然,所装货物不能超过车的容量,且同一种物品不得拿走多件。
这个问题可仿照0 / 1背包问题进行建模,其中车对应于背包,货物对应于物品。
0 / 1背包问题有好几种贪婪策略,每个贪婪策略都采用多步过程来完成背包的装入。
在每一步过程中利用贪婪准则选择一个物品装入背包。
一种贪婪准则为:从剩余的物品中,选出可以装入背包的价值最大的物品,利用这种规则,价值最大的物品首先被装入(假设有足够容量),然后是下一个价值最大的物品,如此继续下去。
这种策略不能保证得到最优解。
例如,考虑n=2, w=[100,10,10], p =[20,15,15], c = 1 0 5。
当利用价值贪婪准则时,获得的解为x= [ 1 , 0 , 0 ],这种方案的总价值为2 0。
而最优解为[ 0 , 1 , 1 ],其总价值为3 0。
另一种方案是重量贪婪准则是:从剩下的物品中选择可装入背包的重量最小的物品。
0-1背包问题动态规划详解及代码

0/1 背包问题动态规划详解及C代码动态规划是用空间换时间的一种方法的抽象。
其关键是发现子问题和记录其结果。
然后利用这些结果减轻运算量。
比如01背包问题。
/* 一个旅行者有一个最多能用M公斤的背包,现在有N件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为P1,P2,...,Pn.若每种物品只有一件求旅行者能获得最大总价值。
输入格式:M,NW1,P1W2,P2......输出格式:X*/因为背包最大容量M未知。
所以,我们的程序要从1到M一个一个的试。
比如,开始任选N 件物品的一个。
看对应M的背包,能不能放进去,如果能放进去,并且还有多的空间,则,多出来的空间里能放N-1物品中的最大价值。
怎么能保证总选择是最大价值呢?看下表。
测试数据:10,33,44,55,6c[i][j]数组保存了1,2,3号物品依次选择后的最大价值.这个最大价值是怎么得来的呢?从背包容量为0开始,1号物品先试,0,1,2,的容量都不能放.所以置0,背包容量为3则里面放4.这样,这一排背包容量为4,5,6,....10的时候,最佳方案都是放4.假如1号物品放入背包.则再看2号物品.当背包容量为3的时候,最佳方案还是上一排的最价方案c为4.而背包容量为5的时候,则最佳方案为自己的重量5.背包容量为7的时候,很显然是5加上一个值了。
加谁??很显然是7-4=3的时候.上一排 c3的最佳方案是4.所以。
总的最佳方案是5+4为9.这样.一排一排推下去。
最右下放的数据就是最大的价值了。
(注意第3排的背包容量为7的时候,最佳方案不是本身的6.而是上一排的9.说明这时候3号物品没有被选.选的是1,2号物品.所以得9.)从以上最大价值的构造过程中可以看出。
f(n,m)=max{f(n-1,m), f(n-1,m-w[n])+P(n,m)}这就是书本上写的动态规划方程.这回清楚了吗?下面是实际程序(在VC 6.0环境下通过):#include<stdio.h>int c[10][100];/*对应每种情况的最大价值*/int knapsack(int m,int n){int i,j,w[10],p[10];printf("请输入每个物品的重量,价值:\n");for(i=1;i<=n;i++)scanf("%d,%d",&w[i],&p[i]);for(i=0;i<10;i++)for(j=0;j<100;j++)c[i][j]=0;/*初始化数组*/for(i=1;i<=n;i++)for(j=1;j<=m;j++){if(w[i]<=j) /*如果当前物品的容量小于背包容量*/{if(p[i]+c[i-1][j-w[i]]>c[i-1][j])/*如果本物品的价值加上背包剩下的空间能放的物品的价值*//*大于上一次选择的最佳方案则更新c[i][j]*/c[i][j]=p[i]+c[i-1][j-w[i]];elsec[i][j]=c[i-1][j];}else c[i][j]=c[i-1][j];}return(c[n][m]);}int main(){int m,n;int i,j;printf("请输入背包的承重量,物品的总个数:\n");scanf("%d,%d",&m,&n);printf("旅行者背包能装的最大总价值为%d",knapsack(m,n)); printf("\n");return 0;}。
动态规划算法0-1背包问题课件PPT

回溯法
要点一
总结词
通过递归和剪枝来减少搜索空间,但仍然时间复杂度高。
要点二
详细描述
回溯法是一种基于递归的搜索算法,通过深度优先搜索来 找出所有可能的解。在0-1背包问题中,回溯法会尝试将物 品放入背包中,并递归地考虑下一个物品。如果当前物品 无法放入背包或放入背包的总价值不增加,则剪枝该分支 。回溯法能够避免搜索一些无效的组合,但仍然需要遍历 所有可能的组合,时间复杂度较高。
缺点
需要存储所有子问题的解,因此空间 复杂度较高。对于状态转移方程的确 定和状态空间的填充需要仔细考虑, 否则可能导致错误的结果。
04
0-1背包问题的动态规划解法
状态定义
状态定义
dp[i][ j]表示在前i个物品中选,总 重量不超过j的情况下,能够获得 的最大价值。
状态转移方程
dp[i][ j] = max(dp[i-1][ j], dp[i1][ j-w[i]] + v[i]),其中w[i]和v[i] 分别表示第i个物品的重量和价值。
02
计算时间复杂度:时间复杂度是指求解问题所需的时间与问题规模之间的关系。对 于0-1背包问题,时间复杂度主要取决于状态总数。由于每个状态都需要被遍历, 因此时间复杂度为O(2^n),其中n是物品的数量。
03
空间复杂度:空间复杂度是指求解问题所需的空间与问题规模之间的关系。在0-1 背包问题中,空间复杂度主要取决于状态总数。由于每个状态都需要被存储,因此 空间复杂度也为O(2^n),其中n是物品的数量。
06
0-1背包问题的扩展和实际应用
多多个物品和多个 背包,每个物品有各自的重量和价值, 每个背包有各自的容量,目标是选择物 品,使得在不超过背包容量限制的情况 下,所选物品的总价值最大。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验报告7课程数据结构与算法实验名称动态规划(四) 第页班级10计本学号105032010111 姓名陈兴灶实验日期:2012年4月09日报告退发(订正、重做)一、实验目的掌握动态规划的原理和应用。
二、实验环境1、微型计算机一台2、WINDOWS操作系统,Java SDK,Eclipse开发环境三、实验内容必做题:1、给定n种物品和一背包。
物品i的重量是wi,其价值为vi,背包的容量为C。
问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?假设i的取值从1开始。
2、给定一个数列,该数列中,元素值可能为正也可能为负,请设计一个程序,求该序列中一个子序列,该子序列元素之和最大。
附加题:1、如以下的左图所示,现有一个矩形序列,这些矩形宽度为1,请设计程序,求这些矩形序列合并而成的最大矩形面积。
上图中的矩形高度分别为:2 1 4 5 1 3 3,最优解为上图中左图所示,最优值为:8四、实验步骤和结果第一题:01背包问题package shiyan_7;import java.util.Scanner;public class ZOP {static int[] weight;static int[] value;static int n;static int c;static int[][] b;public static void Maxvalue(int[] weight, int[] value, int c,int[][] b) {for(int i=0;i<=n;i++){b[0][i]=0;b[i][0]=0;}for(int i=1;i<=n;i++)for(int j=1;j<=c;j++){if(j<weight[i])b[i][j]=b[i-1][j];else{int w=j-weight[i];if(b[i-1][j]>b[i-1][w]+value[i])b[i][j]=b[i-1][j];else b[i][j]=b[i-1][w]+value[i];}}}public static void main(String[] args){Scanner sc=new Scanner(System.in);System.out.println("请输入物品的总个数:");n=sc.nextInt();System.out.println("请输入背包的容量:");c=sc.nextInt();weight=new int[n+1];value=new int[n+1];b=new int[n+1][c+1];System.out.println("请输入各个物品的重量:");for(int i=1;i<=n;i++){weight[i]=sc.nextInt();}System.out.println("请输入各个物品的价值:");for(int j=1;j<=n;j++){value[j]=sc.nextInt();}Maxvalue(weight,value,c,b);System.out.println("背包问题的最优值:"+b[n][c]);}}结果:第二题:求子序列元素和最大package shiyan_7;import java.util.Scanner;public class SumMax1 {public static int []a;public static int []start;public static int []end;public static int n;public static int t;public static int s=0;public static int e=0;public static int max[];public static int k=1;public static void summax(int []a) {for(int i=0;i<n;i++){if(a[i]>=0){e=i;max[k]+=a[i];t=max[k];if(max[k-1]>t){e=i-2;t=max[k-1];}}else if(a[i]<0&&max[k]+a[i]>=0){int j=k;k++;max[k]+=max[j]+a[i];}else{k++;}}}public static void main(String []args){Scanner sc=new Scanner(System.in);System.out.println("输入数组长度");n=sc.nextInt();a=new int [n];System.out.println("输入数组各元素");for(int i=0;i<n;i++)a[i]=sc.nextInt();max=new int [n+1];summax(a);System.out.println("输出最大值");System.out.println(t);System.out.println("输出最优解(从后往前输出)");int i=e,b=0;while(i>=0&&b!=t){System.out.print(a[i]+" ");b=b+a[i];i--;}}}结果:第三题:package shiyan_7;import java.util.Arrays;public class Longest {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubint[][] c = { //该数组用来存放区域内各点高度{ 1, 2, 3, 4, 5 },{ 16, 17, 18, 19, 6 },{ 15, 24, 25, 20, 7 },{ 14, 23, 22, 21, 8 },{ 13, 12, 11, 10, 9 }};int[][] m = new int[c.length][c.length];//该数组用来存放最优值,m[i][j]存放区域中第i行第j列点为起始的最长坡长initArraym_pre(m);//对m数组进行初始化,将各元素初始化为0int[][] pre = new int[c.length][c.length];//该数组用来存放每点的最优值对应的前驱结点,用来构造最优解,0表示该点没有前驱,1表示前驱点在右,2表示前驱点在左,3表示前驱点在上,4表示前驱点在下。
initArraym_pre(pre);//对pre数组进行初始化,全部初始化为0Element[] e = new Element[c.length * c.length];//该数组用来存放区域的每个点信息对象,该信息对象包含描述一个区域点所需要的信息,共3个成员:区域i,j坐标和该点高度initArrare(c, e);//对数组e进行初始化,为区域中的每个点生成一个信息对象,存入数组e中,且对数组中e的元素按照点的高度进行排序longestLRUP(c, m, pre, e);//求以各点为起点的最长坡长,结果存入m中,且将最优值对应的前驱结点存入pre中,用来构造最优解。
show2DArray(m);show2DArray(pre);System.out.println(longest(m));//显示问题最优值,即区域最长下坡showLongestRoute(c, m, pre);//显示问题最优解}private static void show2DArray(int[][] m) {// TODO Auto-generated method stubfor (int i = 0; i < m.length; i++) {for (int j = 0; j < m.length; j++) {System.out.print(m[i][j]+" ");}System.out.println();}}private static void showLongestRoute(int[][] c, int[][] m, int[][] pre) {//该方法利用求最优值过程中得到的信息构造问题最优解Element startPoint = longesStarttPoint(c, m);//先确定最长坡长的起始点的信息对象int i = startPoint.i;//起始点i坐标int j = startPoint.j;//起始点j坐标System.out.print(c[i][j]+" ");//显示起始点while (pre[i][j] != 0) {//该循环根据pre数组,依次的显示出最长坡长上的每个点的高度switch(pre[i][j]){case 1://如果值为1表示前驱点为左边点j--;break;case 2://如果值为2表示前驱点为右边点j++;break;case 3://如果值为3表示前驱点为上边点i--;break;case 4://如果值为4表示前驱点为下边点i++;break;}System.out.print(c[i][j] + " ");}}private static Element longesStarttPoint(int[][] c, int[][] m) { //该方法用来求最长坡长的起始点,返回该点的信息对象int currentI = 0;int currentJ = 0;int currentLongest = 0;for (int i = 0; i < m.length; i++) {for (int j = 0; j < m.length; j++) {if (currentLongest < m[i][j]) {currentLongest = m[i][j];currentI = i;currentJ = j;}}}return new Element(currentI, currentJ, c[currentI][currentJ]);}private static int longest(int[][] m) {//该方法返回问题的最优值int currentLongest = 0;for (int i = 0; i < m.length; i++) {for (int j = 0; j < m.length; j++) {if (currentLongest < m[i][j])currentLongest = m[i][j];}}return currentLongest;}private static void longestLRUP(int[][] c, int[][] m, int[][] pre, Element[] e) {//该方法为关键方法,求问题的最优值,并保存到中,同时将各点最优值前驱放入到per中for (int i = 0; i < e.length; i++) {//依次取出数组e中的每一个点,这些点是按照高度从小到大排好序Element x = e[i];int left = 0;int right = 0;int up = 0;int down = 0;int max = 0;if (x.j > 0) {//要注意最左边的点没有左边点if (x.h > c[x.i][x.j - 1])left = m[x.i][x.j - 1];if (max < left) {max = left;pre[x.i][x.j] = 1;}}if (x.j < c.length - 1) {//要注意最右边点没有右边点if (x.h > c[x.i][x.j + 1])right = m[x.i][x.j + 1];if (max < right) {max = right;pre[x.i][x.j] = 2;}}if (x.i > 0) {//要注意最上边点没有上边点if (x.h > c[x.i - 1][x.j])up = m[x.i - 1][x.j];if (max < up) {max = up;pre[x.i][x.j] = 3;}}if (x.i < c.length - 1) {//要注意最下边点没有下边点if (x.h > c[x.i + 1][x.j])down = m[x.i + 1][x.j];if (max < down) {max = down;pre[x.i][x.j] = 4;}}m[x.i][x.j]=max+1;}}private static void initArraym_pre(int[][] m_pre) { //对参数m_pre对应的二维数组进行初始化,将所有元素初始化为0 for (int i = 0; i < m_pre.length; i++) {for (int j = 0; j < m_pre.length; j++) {m_pre[i][j] = 0;}}}private static void initArrare(int[][] c, Element[] e) { //利用区域原始数据来初始化数组e,即对数组c中的每个点,构造该点信息对象,且存入数组e中int k = 0;for (int i = 0; i < c.length; i++) {for (int j = 0; j < c.length; j++) {e[k++] = new Element(i, j, c[i][j]);}}Arrays.sort(e);//对数组e元素根据点的高度进行排序}}package shiyan_7;public class Element implements Comparable<Element> {//区域点信息类,必须实现Comparable接口int i;//点的i坐标int j;//点的j坐标int h;//点的高度public Element(int i, int j, int h) {super();this.i = i;this.j = j;this.h = h;}@Overridepublic int compareTo(Element e) {//因为要对这个类的对象进行排序,所以该类需要实现Comparable接口//此方法为该接口申明的方法,子类中必须实现,当使用Arrays的sort方法对该类对象进行排序时//会调用该对象的此方法,进行对象间的比较,根据比较结果排序if (e.h > this.h)return -1;//返回负数,表示当前对象小if (e.h < this.h)return 1;//返回正数,表示当前对象大return 0;//返回零,表示两个对象大小相等}}结果:附加题:package shiyan_7;import java.util.Scanner;public class AreaMax {public static int [][]b;public static int k;public static int n;public static int r;public static int []max;public static int []x;public static int []y;public static void areamax(int []a) {for (int i = 1; i<=n; i++)b[i][i-1]=0;for(int i=1;i<=n;i++){ int t=b[i][i-1];int e=a[i];for (int j =i;j<=n;j++){if(a[j]<e)e=a[j];b[i][j]=(j-i+1)*e;if(t<b[i][j]){t=b[i][j];y[i]=j;}}max[i]=t;}}public static int max(int []a){i nt m=max[1];k=1;f or(int i=2;i<=n;i++)if(m<max[i]){m=max[i];k=i;}r eturn m;}public static void main(String[] args) {// TODO Auto-generated method stubScanner sc=new Scanner(System.in);System.out.println("输小长方形个数(每个小长方形的底为1)");n=sc.nextInt();int []a=new int [n+1];b=new int [n+1][n+1];max=new int [n+1];y=new int [n+1];System.out.println("输入各小长方形的高");for(int i=1;i<=n;i++){a[i]=sc.nextInt();}areamax(a);System.out.println("输出最大值");System.out.println(max(max));System.out.println("最优解为");for(int i=k;i<=y[k];i++)System.out.print(a[i]+" ");}}结果:五、实验总结一、本次实验让我认识到了:我对动态规化的认识远远不够,因为用了穷举法还不知道是怎么回事,后来经老师指导才明白,原来是有重复运算。