贪心法 背包问题副本.docx
《贪心法 背包问题副本.docx》由会员分享,可在线阅读,更多相关《贪心法 背包问题副本.docx(32页珍藏版)》请在冰豆网上搜索。
贪心法背包问题副本
课程设计(论文)
题目
贪心法:
背包问题
姓名
学号
指导老师
指导教师职称
教授
年级专业班级
所在学院
理学院
2014年4月25日
目录
目录1
摘要2
前言3
1课题背景4
1.1背景4
1.2需求分析5
1.3贪心法介绍以及注意事项…………………………………………………..…5
1.4意义6
1.5文献综述…………………………………………………………………..…….6
2设计简介及设计方案论述7
2.1设计简介7
2.2设计方案论述7
3详细设计………………..…………………………………………….………......8
3.1物品的存储和链队结点的定义8
3.2物品链队结点全局头指针的定义8
3.3物品链队的入队和出对操作……………..……….......................................9
3.4菜单的设计………..…………………………………………………………….9
4设计结果及分析16
4.1测试结果18
4.2问题解决………..……………………………………………………………..18
5总结20
致谢22
参考文献23
附录程序代码24
摘要
本课题主要是运用VC6.0,开发基于控制台下的贪心法背包问题的选择程序。
本文较详细地介绍了这一程序的设计思想,功能结构以及队列的设计和某些功能函数的设计。
本文还给出了对这一程序的测试情况以及对测试结果的分析。
关键词:
GoodsEnQueue,GoodsDeQueue,head,算法与数据结构
前言
本文详细介绍了贪心法背包问题的设计与开发。
全文共5章。
第1章介绍了贪心法背包问题的背景,以及它所要实现的基本功能。
并根据这些用户需求,进行了必要的需求分析,从而确定了该程序应实现了一些基本功能。
本章中,还简要地介绍了该程序开发的意义以及在整个开发过程中,我们所查阅并借用的一些参考文献的主要内容。
第2章主要介绍了贪心法背包问题程序中各功能模块的总体框图,主要链队的设计以及各链队之间的相互关系,这是全文的核心部分。
第3章是贪心法背包问题程序的详细设计,我们给出了主要链队的设计,关于链队的入队和出队问题,并给出了其程序。
第4章是对所开发的背包问题程序的运行测试。
通过我们所设计的部分测试数据,检验程序是否达到了预定的设计要求。
第5章是对关于运用贪心法解决背包问题程序开发过程的总结。
总结了本次课程设计的意义,以及测试中所发现的一些问题,有待进一步改进的地方。
重点还谈到了我在本次课程设计中的收获与感想。
全文的最后是致谢、参考文献和程序的全部源代码。
XX
2014-4-25于武汉工程大学理学院
课题背景
2.1背景
有一容量为200(米3)的背包,8种物品的编号、体积和价值如下表所示。
现要将物品装进背包,要求不能超过背包的容量且物品总价值最大,该如何装包?
编号
体积(单位:
米3)
价值(单位:
元)
1
40
35
2
55
20
3
20
20
4
65
40
5
30
35
6
40
15
7
45
40
8
35
20
很容易想到3种贪心策略:
1每次取价值最大的物品;
2每次取体积最小的物品;
3每次取单位体积价值最大的物品。
2.2需求分析
根据上面给出的问题,我们可以运用贪心法和链队操作来解决。
而且,我们必须通过程序来实现上面背包问题的3种贪心策略,并与之做出比较,选出最好的策略。
2.3贪心法介绍及注意事项
(1)多阶段决策问题、无后向性与最优化原理
多阶段决策问题是指这样一类问题:
问题的解决过程可以分为若干阶段,在每一阶段都做出相应的决策,所有决策构成的决策序列就是问题的解决方案。
多阶段决策问题有一个共同特点:
每一阶段面临的问题都是原问题的一个子问题,而且子问题的解决只与当前阶段和以后阶段的决策有关,与以前各阶段的决策无关。
我们称这类问题具有无后向性的特点。
所谓最优化原理,是说一个问题的最优策略有这样的一个性质,不论以前的决策如何,对于当前的子问题,其余的决策一定构成最优策略。
最优化原理可以简单地描述为:
一个最优策略的子策略总是最优的。
一个问题满足最优化原理,又称它为具有最优子结构性质。
例如,4个城市A、B、C、D间的道路如下图所示:
如果A到D的最短路线为A→B→D,那么B到D的最短路线为B→D。
可以用反证法证明:
如果B到D的最短路线不是B→D,假设另一条路径B=>D更短,那么A→B=>D就比A→B→D更短,与题设矛盾。
所以B→D是B到D的最短路线。
在解决背包问题时,运用了这样的一种策略,就是在求最优解过程的每一步都采用一种局部最优的策略,即优先考虑将价值密度大的物品放入背包,把问题的范围和规模缩小,最后把每一步的结果合并起来得到一个最优解。
归纳起来,运用贪心法解题的一般步骤是:
1从问题的某个初始解出发。
2采用循环语句,当可以向求解目标前进一步时,就根据局部最优策略,得到一个部分解,缩小问题的范围或规模。
3将所有部分解综合起来,得到问题的最优解。
(2)用贪心法解题的注意事项
一个多阶段决策问题如果满足最优化原理,就可以考虑使用贪心法来解。
如果这个条件不是那么明显,在解题前应该先进行证明,有时可能还要对原题进行一些转化才行。
要注意的是,一个问题具有无后向性特点,不一定就满足最优化原理。
而一个问题满足最优化原理,也不一定就能用贪心法求解。
例如,某国家的货币体系包含n种面值(其中一定有面值为1的),现有一种商品价格为p,请问最少用多少枚货币可以正好买下?
该问题满足最优化原理。
如果试图用贪心法来解,一个很容易想到的贪心策略是:
尽量用面值大的的货币。
这个策略在很多情况下是有效的。
例如我国的货币体系为{1,2,5,10,20,50,100}。
又如美国的货币体系为{1,5,10,25,100}。
这一策略总能得到最优解。
但如果某国家的货币体系为{1,5,8,10},p=13,则这一贪心策略得到的结果是4枚货币,而值分别为10、1、1、1,而最优策略是2枚货币,面值为8和5。
贪心法失效了。
很可惜,目前并没有一个一般性的结论,可以保证贪心法一定得到问题的最优解。
因此,在应用贪心法之前,应该先论证当前的策略能否得到问题的最优解。
对于上面的货币问题,贪心法并不能保证得到最优解。
一般需用动态规划方法来解决。
有些问题能应用贪心法来解,但需要选择适当的局部最优策略,才能得到正确结果。
1.4意义
关于贪心法的相关知识,是我们信息与计算科学专业必须了解的经典算法之一。
它在程序中的作用肯定是毋庸置疑,对于我们以后的工作有时也有着指导作用。
采用C++算法与数据结购的思想,设计与开发背包问题的算法程序,有助于我们了解对该门课程的掌握程度及自身的运用学习能力。
2.4文献综述
文献[1]较详细地介绍了贪心法背包问题程序的设计与开发以及C++的一些基本知识,它对于我们了解C++知识,运用C++进行算法与数据结构有非常直接的帮助。
文献[2]介绍了C++程序设计的主要思想与方法,在解决贪心法背包问题程序时,我们参考该书中许多技巧以及接口程序的设计,链队的操作等。
设计简介及设计方案论述
2.5设计简介
根据需求分析,我们将设计三个策略程序:
1每次取价值最大的物品;
2每次取体积最小的物品;
3每次取单位体积价值最大的物品。
其物品链队操作结构见图2-1,其功能结构见其图2-2。
GoodsEnqueue(含参数)
GoodsDequeue(含参数)
Goods2Enqueue(含参数)
GoodsDequeue(含参数)
Goods3Enqueue(含参数)
GoodsDequeue(含参数)
图2-1入队和出队的结构
背包问题系统:
背包问题贪心策略
1每次取价值最大的物品
2每次取体积最小的物品
3每次取单位体积价值最大的物品
4退出程序
图2-2系统的功能结构
2.6设计方案论述
背包问题中的物品用数组进行存储,然后通过链队的入队操作进行简单的升序或降序排列,再通过出队操作去进行其他程序操作。
在主函数中通过switch函数做出3种贪心策略的选择操作,并实现其功能。
详细设计
2.7物品的存储和链队结点的定义
DoubleGoods[N][3]={{1,40,35},{2,55,20},{3,20,20},{4,65,40},{5,30,35},{6,40,15},{7,45,40},{8,35,20}};
structNode//链队结点
{
doublenum;//物品编号
doublevolume;//物品体积
doublevalue;//物品价值
doublev;//单位体积价值
structNode*next;
};
2.8物品链队结点全局头指针的定义
//定义物品链队全局头指针
Node*head=NULL;
2.9物品链队的入队和出对操作
//物品依价值按升序入链队
voidGoodsEnQueue(doublenum,doublevolume,doublevalue)
{Node*p,*q,*rear,*newnode;
//生成新结点
newnode=newNode;
newnode->num=num;
newnode->volume=volume;
newnode->value=value;
newnode->next=NULL;
//入链队
if(head==NULL)//空链队
head=newnode;
else//非空链队
{//寻找链尾结点
p=head;
while(p->next!
=NULL)
p=p->next;
rear=p;
if(newnode->valuevalue)//插链头
{newnode->next=head;
head=newnode;
}
elseif(newnode->value>=rear->value)//插链尾
rear->next=newnode;
else
{//插中间
p=head;
while(newnode->value>=p->value)
{q=p;
p=p->next;
}
newnode->next=q->next;
q->next=newnode;
}
}
}
//物品依体积按降序序入链队
voidGoods2EnQueue(doublenum,doublevolume,doublevalue)
{Node*p,*q,*rear,*newnode;
//生成新结点
newnode=newNode;
newnode->num=num;
newnode->volume=volume;
newnode->value=value;
newnode->next=NULL;
//入链队
if(head==NULL)//空链队
head=newnode;
else//非空链队
{//寻找链尾结点
p=head;
while(p->next!
=NULL)
p=p->next;
rear=p;
if(newnode->volume>head->volume)//插链头
{newnode->next=head;
head=newnode;
}
elseif(newnode->volume<=rear->volume)//插链尾
rear->next=newnode;
else
{//插中间
p=head;
while(newnode->volume<=p->volume)
{q=p;
p=p->next;
}
newnode->next=q->next;
q->next=newnode;
}
}
}
//物品依单位体积按降序序入链队
voidGoods3EnQueue(doublenum,doublevolume,doublevalue,doublev)
{Node*p,*q,*rear,*newnode;
//生成新结点
newnode=newNode;
newnode->num=num;
newnode->volume=volume;
newnode->value=value;
newnode->v=v;
newnode->next=NULL;
//入链队
if(head==NULL)//空链队
head=newnode;
else//非空链队
{//寻找链尾结点
p=head;
while(p->next!
=NULL)
p=p->next;
rear=p;
if(newnode->v>head->v)//插链头
{newnode->next=head;
head=newnode;
}
elseif(newnode->v<=rear->v)//插链尾
rear->next=newnode;
else
{//插中间
p=head;
while(newnode->v<=p->v)
{q=p;
p=p->next;
}
newnode->next=q->next;
q->next=newnode;
}
}
}
voidGoodsDeQueue(double&num,double&volume,double&value)
{Node*p;//探测指针
if(IsEmpty(head))//如果链队为空
{cout<<"物品链队空,无法出队!
"<return;
}
elseif(head->next==NULL)//链队仅有惟一结点
{p=head;
num=p->num;
volume=p->volume;
value=p->value;
head=NULL;//将链队置空
deletep;//删除链队头结点
}
else//链队具有两个以上结点
{p=head;
num=p->num;
volume=p->volume;
value=p->value;
head=head->next;//链队头指针指向下一个结点
deletep;//删除链队头结点
}
}
3.4菜单的设计
voidMenu()
{
cout<<"________________________"<cout<<"背包问题贪心策略"<cout<<"\n1每次取价值最大的物品"<cout<<"\n2每次取体积最小的物品"<cout<<"\n3每次取单位体积价值最大的物品"<cout<<"\n4退出程序"<cout<<"________________________"<cout<<"请输入相对有的数字:
"<}
设计结果及分析
2.10测试结果
图4-1-1程序运行后显示的菜单
图4-1-2策略1的输出结果
图4-1-3策略2的输出结果
图4-1-4策略3的输出结果
通过图形比较,我们能够知道第3种贪心策略是最好的。
2.11问题解决
通过菜单函数不能连续按数字实现程序功能?
解决办法:
在主函数中初始化GoodsValue=0,GoodsVolume=0不能放在do循环之外,而应放在其里面。
总结
贪心法在求解过程的每一步都采取局部最优策略,使问题的规模一步步缩小,期望每一步的局部最优达到最后总体上的全局最优。
但是有时局部最优并不能保证全局最优,这是采用贪心法时要注意的地方;最优化原理可简述为:
一个最优策略的子策略总是最优的;一个多阶段决策问题如果满足最优化原理,则可考虑用贪心法求解,否则须先行证明而后采用,或者要对原题进行某种转化才可使用,也可能根本就不可用,这要看是否满足最优化原理。
这次课程设计,是我与同学一起第一次合作完成较大的程序编写,开始时,我们心里根本没底,想都不敢想自已能写出一点东西来,并真正地解决这一实际问题。
但随着工作的逐渐深入,对问题的理解越来越透彻,想写的东西越来越多,信心越来越足,程序越编越大,系统的功能越做越强。
当我们洋洋洒洒地撰写完千余行代码,将一个又一个功能模块实现出来,并将它们调试通过之后,那种喜悦感、幸福感、成就感让我感到兴奋。
我终于等到了所谓“开窍”的这一刻,原来它是这样的一种感觉。
此时此刻,回想一年来学习编程的经历,我明白了这样一个道理:
此时的喜悦感、幸福感、成就感,不正好是过去的沮丧、痛苦、自卑所带来的馈赠吗!
其实,这种道理对我们这个年龄段的青年人,谁人不知又谁人不晓呢,它所应证的不就是那几句老名言吗?
不经历风雨,怎么能见彩虹
宝剑锋从磨砺出,梅花香自苦寒来
让我们值得进一步思考的是,为什么我们一碰到困难,就忘记了这些至理名言呢?
为什么我们一遇到挫折,总希望别人来安慰与鼓励,甚至是扶你前行呢?
通过学习算法与数据结构,我们了解到电脑上的许多东西都可以用算法来进行实现。
在老师的严格教导下,我们从中收获颇多。
像什么单链表操作及队列操作的学习和编程,对于它们,我们已经有了一定的了解。
以后的学习,我们应更加刻苦钻研。
平时学习不够扎实,没有刻苦的钻研,就会导致我们这次的诸多不顺。
这次的苦果是我们咎由自取,我想我们应该要更加学习了,虽然说出来比较容易,但真的要学习了。
没有一个人会喜欢自己做得很差,相反地,任何人都希望做得最好。
不过,在我的词典里,没有最好,只有更好。
伟大的科学家爱因斯坦说过,成功等于99%的努力加1%的灵感。
在得到这些荣誉的前提下,我们必须付出珍贵的时间和辛勤的汗水。
致谢
一份课程设计的总结,一份对老师的感谢。
虽然我们课程设计程序代码在这学期开始的时候已经有了,但是在明天即将给老师的时刻,程序代码也发生了许多变化,功能也逐渐提高;一些变化,一些收获。
老师说过:
“道虽远,不行不至;事虽难,不为不成。
”这专业真的很累,老师们累,学生们也累,谢谢老师们和我们一起坚持着。
明天结果如何是无法知道的,而今天我们都努力过。
参考文献
[1]《C++程序设计》(第二版),谭浩强著,清华大学出版社
[2]《程序设计基础》(第三版),吴文虎徐明星编著,清华大学出版社
附录程序代码
#include
usingnamespacestd;
#defineM200//背包体积容量为200
#defineN8//物品序号
doubleGoods[N][3]={{1,40,35},{2,55,20},{3,20,20},{4,65,40},{5,30,35},{6,40,15},{7,45,40},{8,35,20}};
structNode//链队结点
{
doublenum;//物品编号
doublevolume;//物品体积
doublevalue;//物品价值
doublev;//单位体积价值
structNode*next;
};
//定义物品链队全局头指针
Node*head=NULL;
//判空
intIsEmpty(Node*head)
{
if(head==NULL)
return1;
else
return0;
}
//物品依价值按升序入链队
voidGoodsEnQueue(doublenum,doublevolume,doublevalue)
{Node*p,*q,*rear,*newnode;
//生成新结点
newnode=newNode;
newnode->num=num;
newnode->volume=volume;
newnode->value=value;
newnode->next=NULL;
//入链队
if(head==NULL)//空链队
head=newnode;
else//非空链队
{//寻找链尾结点
p=head;
while(p->next!
=NULL)
p=p->next;
rear=p;
if(newnode->valuevalue)//插链头
{newnode->next=head;
head=newnode;
}
elseif(newnode->value>=rear->value)//插链尾
rear->next=newnode;
else
{//插中间
p=head;
while(newnode->value>=p->value)
{q=p;
p=p->next;
}
newnode->next=q->next;
q->next=newnode;
}
}
}
//物品依体积按降序序入链队
voidGoods2EnQueue(doublenum,doublevolume,doublevalue)
{Node*p,*q,*rear,*newnode;
//生成新结点
newnode=newNode;
newnode->num=num;
newnode->volume=volume;
newnode->value=value;
newnode->next=NULL;
//入链队
if(head==NULL)//空链队
head=newnode;
else//非空链队
{//寻找链尾结点
p=head;
while(p->next!
=NULL)
p=p->next;
rear=p;
if(newnode->volume>head->volume)//插链头
{newnode->next=head;
head=newnode;
}
elseif(newnode->volume<=rear->volume)//插链尾
rear->next=newnode;
else
{//插中间
p=head;
while(newnode->volume<=p->volume)
{q=p;
p=p->next;
}
newnode->next=q->next;
q->next=newnode;
}
}
}
//物品依单位体积按降序序入链队
voidGoods3EnQueue(doublenum,doublevolume,doublevalue,doublev)
{Node*p,*q,*rear,*newnode;
//生成新结点
newnode=newNode;
newnode->num=num;
newnode->volume=vo