10计本算法最大矩阵和01背包问题.docx
《10计本算法最大矩阵和01背包问题.docx》由会员分享,可在线阅读,更多相关《10计本算法最大矩阵和01背包问题.docx(18页珍藏版)》请在冰豆网上搜索。
10计本算法最大矩阵和01背包问题
实验报告7
课程数据结构与算法实验名称动态规划(四)第页
班级10计本学号105032010111姓名陈兴灶
实验日期:
2012年4月09日报告退发(订正、重做)
一、实验目的
掌握动态规划的原理和应用。
二、实验环境
1、微型计算机一台
2、WINDOWS操作系统,JavaSDK,Eclipse开发环境
三、实验内容
必做题:
1、给定n种物品和一背包。
物品i的重量是wi,其价值为vi,背包的容量为C。
问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
假设i的取值从1开始。
2、给定一个数列,该数列中,元素值可能为正也可能为负,请设计一个程序,求该序列中一个子序列,该子序列元素之和最大。
附加题:
1、如以下的左图所示,现有一个矩形序列,这些矩形宽度为1,请设计程序,求这些矩形序列合并而成的最大矩形面积。
上图中的矩形高度分别为:
2145133,最优解为上图中左图所示,最优值为:
8
四、实验步骤和结果
第一题:
01背包问题
packageshiyan_7;
importjava.util.Scanner;
publicclassZOP{
staticint[]weight;
staticint[]value;
staticintn;
staticintc;
staticint[][]b;
publicstaticvoidMaxvalue(int[]weight,int[]value,intc,int[][]b)
{
for(inti=0;i<=n;i++)
{
b[0][i]=0;
b[i][0]=0;
}
for(inti=1;i<=n;i++)
for(intj=1;j<=c;j++)
{
if(jb[i][j]=b[i-1][j];
else
{
intw=j-weight[i];
if(b[i-1][j]>b[i-1][w]+value[i])
b[i][j]=b[i-1][j];
elseb[i][j]=b[i-1][w]+value[i];
}
}
}
publicstaticvoidmain(String[]args)
{
Scannersc=newScanner(System.in);
System.out.println("请输入物品的总个数:
");
n=sc.nextInt();
System.out.println("请输入背包的容量:
");
c=sc.nextInt();
weight=newint[n+1];
value=newint[n+1];
b=newint[n+1][c+1];
System.out.println("请输入各个物品的重量:
");
for(inti=1;i<=n;i++)
{
weight[i]=sc.nextInt();
}
System.out.println("请输入各个物品的价值:
");
for(intj=1;j<=n;j++)
{
value[j]=sc.nextInt();
}
Maxvalue(weight,value,c,b);
System.out.println("背包问题的最优值:
"+b[n][c]);
}
}
结果:
第二题:
求子序列元素和最大
packageshiyan_7;
importjava.util.Scanner;
publicclassSumMax1{
publicstaticint[]a;
publicstaticint[]start;
publicstaticint[]end;
publicstaticintn;
publicstaticintt;
publicstaticints=0;
publicstaticinte=0;
publicstaticintmax[];
publicstaticintk=1;
publicstaticvoidsummax(int[]a)
{
for(inti=0;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];
}
}
elseif(a[i]<0&&max[k]+a[i]>=0)
{
intj=k;
k++;
max[k]+=max[j]+a[i];
}
else
{
k++;
}
}
}
publicstaticvoidmain(String[]args)
{
Scannersc=newScanner(System.in);
System.out.println("输入数组长度");
n=sc.nextInt();
a=newint[n];
System.out.println("输入数组各元素");
for(inti=0;ia[i]=sc.nextInt();
max=newint[n+1];
summax(a);
System.out.println("输出最大值");
System.out.println(t);
System.out.println("输出最优解(从后往前输出)");
inti=e,b=0;
while(i>=0&&b!
=t)
{
System.out.print(a[i]+"");
b=b+a[i];
i--;
}
}
}
结果:
第三题:
packageshiyan_7;
importjava.util.Arrays;
publicclassLongest{
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
int[][]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=newint[c.length][c.length];//该数组用来存放最优值,m[i][j]存放区域中第i行第j列点为起始的最长坡长
initArraym_pre(m);//对m数组进行初始化,将各元素初始化为0
int[][]pre=newint[c.length][c.length];//该数组用来存放每点的最优值对应的前驱结点,用来构造最优解,0表示该点没有前驱,1表示前驱点在右,2表示前驱点在左,3表示前驱点在上,4表示前驱点在下。
initArraym_pre(pre);//对pre数组进行初始化,全部初始化为0
Element[]e=newElement[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);//显示问题最优解
}
privatestaticvoidshow2DArray(int[][]m){
//TODOAuto-generatedmethodstub
for(inti=0;ifor(intj=0;jSystem.out.print(m[i][j]+"");
}
System.out.println();
}
}
privatestaticvoidshowLongestRoute(int[][]c,int[][]m,int[][]pre){
//该方法利用求最优值过程中得到的信息构造问题最优解
ElementstartPoint=longesStarttPoint(c,m);//先确定最长坡长的起始点的信息对象
inti=startPoint.i;//起始点i坐标
intj=startPoint.j;//起始点j坐标
System.out.print(c[i][j]+"");//显示起始点
while(pre[i][j]!
=0){//该循环根据pre数组,依次的显示出最长坡长上的每个点的高度
switch(pre[i][j]){
case1:
//如果值为1表示前驱点为左边点
j--;
break;
case2:
//如果值为2表示前驱点为右边点
j++;
break;
case3:
//如果值为3表示前驱点为上边点
i--;
break;
case4:
//如果值为4表示前驱点为下边点
i++;
break;
}
System.out.print(c[i][j]+"");
}
}
privatestaticElementlongesStarttPoint(int[][]c,int[][]m){
//该方法用来求最长坡长的起始点,返回该点的信息对象
intcurrentI=0;
intcurrentJ=0;
intcurrentLongest=0;
for(inti=0;ifor(intj=0;jif(currentLongestcurrentLongest=m[i][j];
currentI=i;
currentJ=j;
}
}
}
returnnewElement(currentI,currentJ,c[currentI][currentJ]);
}
privatestaticintlongest(int[][]m){
//该方法返回问题的最优值
intcurrentLongest=0;
for(inti=0;ifor(intj=0;jif(currentLongestcurrentLongest=m[i][j];
}
}
returncurrentLongest;
}
privatestaticvoidlongestLRUP(int[][]c,int[][]m,int[][]pre,Element[]e){
//该方法为关键方法,求问题的最优值,并保存到中,同时将各点最优值前驱放入到per中
for(inti=0;iElementx=e[i];
intleft=0;
intright=0;
intup=0;
intdown=0;
intmax=0;
if(x.j>0){//要注意最左边的点没有左边点
if(x.h>c[x.i][x.j-1])
left=m[x.i][x.j-1];
if(maxmax=left;
pre[x.i][x.j]=1;
}
}
if(x.jif(x.h>c[x.i][x.j+1])
right=m[x.i][x.j+1];
if(maxmax=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(maxmax=up;
pre[x.i][x.j]=3;
}
}
if(x.iif(x.h>c[x.i+1][x.j])
down=m[x.i+1][x.j];
if(maxmax=down;
pre[x.i][x.j]=4;
}
}
m[x.i][x.j]=max+1;
}
}
privatestaticvoidinitArraym_pre(int[][]m_pre){
//对参数m_pre对应的二维数组进行初始化,将所有元素初始化为0
for(inti=0;ifor(intj=0;jm_pre[i][j]=0;
}
}
}
privatestaticvoidinitArrare(int[][]c,Element[]e){
//利用区域原始数据来初始化数组e,即对数组c中的每个点,构造该点信息对象,且存入数组e中
intk=0;
for(inti=0;ifor(intj=0;je[k++]=newElement(i,j,c[i][j]);
}
}
Arrays.sort(e);//对数组e元素根据点的高度进行排序
}
}
packageshiyan_7;
publicclassElementimplementsComparable{//区域点信息类,必须实现Comparable接口
inti;//点的i坐标
intj;//点的j坐标
inth;//点的高度
publicElement(inti,intj,inth){
super();
this.i=i;
this.j=j;
this.h=h;
}
@Override
publicintcompareTo(Elemente){//因为要对这个类的对象进行排序,所以该类需要实现Comparable接口
//此方法为该接口申明的方法,子类中必须实现,当使用Arrays的sort方法对该类对象进行排序时
//会调用该对象的此方法,进行对象间的比较,根据比较结果排序
if(e.h>this.h)
return-1;//返回负数,表示当前对象小
if(e.hreturn1;//返回正数,表示当前对象大
return0;//返回零,表示两个对象大小相等
}
}
结果:
附加题:
packageshiyan_7;
importjava.util.Scanner;
publicclassAreaMax{
publicstaticint[][]b;
publicstaticintk;
publicstaticintn;
publicstaticintr;
publicstaticint[]max;
publicstaticint[]x;
publicstaticint[]y;
publicstaticvoidareamax(int[]a)
{
for(inti=1;i<=n;i++)
b[i][i-1]=0;
for(inti=1;i<=n;i++)
{intt=b[i][i-1];
inte=a[i];
for(intj=i;j<=n;j++)
{
if(a[j]b[i][j]=(j-i+1)*e;
if(t
{
t=b[i][j];
y[i]=j;
}
}
max[i]=t;
}
}
publicstaticintmax(int[]a)
{
intm=max[1];
k=1;
for(inti=2;i<=n;i++)
if(m{
m=max[i];
k=i;
}
returnm;
}
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
Scannersc=newScanner(System.in);
System.out.println("输小长方形个数(每个小长方形的底为1)");
n=sc.nextInt();
int[]a=newint[n+1];
b=newint[n+1][n+1];
max=newint[n+1];
y=newint[n+1];
System.out.println("输入各小长方形的高");
for(inti=1;i<=n;i++)
{
a[i]=sc.nextInt();
}
areamax(a);
System.out.println("输出最大值");
System.out.println(max(max));
System.out.println("最优解为");
for(inti=k;i<=y[k];i++)
System.out.print(a[i]+"");
}
}
结果:
五、实验总结
一、本次实验让我认识到了:
我对动态规化的认识远远不够,因为用了穷举法还不知道是怎么回事,后来经老师指导才明白,原来是有重复运算。
后来重新思考,也写出经效率较高的算法,没有重复运算了,应该是用了动态规化的思想。
二、原来不怎么会调试,经过同学帮助现在已经比较熟练掌握但还须加强。
三、最长下坡一题,因为之前有做过,所以就直接用老师的算法了。
(已经理解)