算法课程设计报告书Word文档格式.docx
《算法课程设计报告书Word文档格式.docx》由会员分享,可在线阅读,更多相关《算法课程设计报告书Word文档格式.docx(14页珍藏版)》请在冰豆网上搜索。
动态规划法、租用游艇问题、回溯法、部落卫队问题、C++
一、动态规划法解决租用游艇问题
1.1问题重述
长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。
有可以游艇出租站用游艇并在下游的任何一个游艇出租站归还游艇。
游艇出租站i到游艇出租站j之间的租金为r(i,j),。
试设计一个算法,计算游艇出租站1到出租站n所需的最少租金。
对于给定的游艇出租站i到游艇出租站j之间的租金为r(i,j),1<
=i<
j<
=n,编程计算从游艇出租站1到游艇出租站n所需的最少租金。
由文件提供输入数据。
文件的第1行中有1个正整数n(n<
=200),表示有n个游艇出租站。
接下来的n-1行是一个半矩阵r(i,j),1<
=n。
程序运行结束时,将计算出的从游艇出租站1到游艇出租站n所需的最少租金输出到文件中。
输入文件示例输出文件示例12
312
515
7
1.2问题分析
将每个出租站看作一个点,站与站之间的关系可以用有向无环图表示,同时站与站之间的租金为边的权。
此问题可转化成求站1到站n的最短路径问题。
用动态规划求解,递推方程如下所示:
定义f[i][j]为站点i到站点j的最少租金。
i<
k<
j,
1<
=i,j<
=n.初始最优解为。
1.3算法原理与设计
1.3.1算法原理
本文主要适用动态规划法的思想求解,其基本思想时将原问题分解为若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
该方法主要应用于最优化问题,这类问题会有多种可能的解,每个解都有一个值,而动态规划找出其中最优(最大或最)值的解。
若存在若干个取最优值的解的话,它只取其中的一个。
在求解过程中,该方法也是通过求解局部子问题的解达到全局最优解,但与分治法和贪心法不同的是,动态规划允许这些子问题不独立,也允许其通过自身子问题的解作出选择,该方法对每一个子问题只解一次,并将结果保存起来,避免每次碰到时都要重复计算。
因此,动态规划法所针对的问题有一个显著的特征,即它所对应的子问题树中的子问题呈现大量的重复。
动态规划法的关键就在于,对于重复出现的子问题,只在第一次遇到时加以求解,并把答案保存起来,让以后再遇到时直接引用,不必重新求解。
设计动态规划法一般包含以下4个步骤为:
◆找出最优解的性质,并刻画其结构特征;
◆递归地定义最优值;
◆以自底向上的方法计算出最优解;
◆根据计算最优值得到的信息,构造最优解。
1.3.2算法设计
intmain()
{
intnum,i,j,k;
for(k=2;
num;
k++)
{
for(i=0;
i<
num-k;
i++)
intmark=i+k;
for(j=i+1;
mark;
j++)
if(list[i][j]+list[j][mark]<
list[i][mark])
list[i][mark]=list[i][j]+list[j][mark];
}
}
cout<
<
list[0][num-1];
return0;
本课设中list[0][n-1]代表所用租金最少,n为游艇出租站的个数。
List[i][j]表示从第i个游艇出租站到第j个游艇出租站的费用(其中i<
j)。
当list[i][j]+list[j][mark]<
list[i][mark]时,list[i][mark]=list[i][j]+list[j][mark]。
则递归方程为
list[0][n-1]=min{list[0][k]+list[k][n-1],list[0][n-1]}
1.4算法实现与结果
程序代码:
#include<
iostream>
vector>
usingnamespacestd;
intmain()
intnum,i,j,k,tmp;
cin>
>
vector<
int>
>
list;
line;
num-1;
list.push_back(line);
for(j=0;
=i;
j++)//在容器前面添加些0,从而使list[i][j]表示从第i个出租站到第j个出租站所需的金额
{//同时也去除无效的表示,比如list[0][0]直接赋值为0,从而使后面的计算更方便
list[i].push_back(0);
tmp;
list[i].push_back(tmp);
//从i+1个出租站到第j+1个出租站所需金额
k++)//从两个出租站开始,逐步计算每几个出租站之间的最优解,最终计算num-1个出租站合并的最优解
intmark=i+k;
list[i][mark])//例如list[0][1]+list[1][2]<
list[0][2],则改变list[0][2]的值
cout<
return0;
1.5结果描述
运行结果如图1.1所示。
图1.1租用游艇问题运行结果
如图1所示,含有3个游艇出租站,从出租站1到出租站2,3分别需要租金为5,15,从出租站2到出租站3需要租金为7,则运用动态规划法求解出从出租站1到出租站3所需最少租金为12。
二、回溯法解决部落卫队问题
2.1问题重述
原始部落byteland中的居民们为了争夺有限的资源,经常发生冲突。
几乎每个居民都是他的仇敌。
部落酋长为了组织一支保卫部落的队伍,希望从部落的居民中选出最多的居民入伍,并保证队伍中任何2个人都不是仇敌。
2.2问题分析
本问题为组织一支队伍保卫部落,并且卫队中任意2人不能有仇敌关系,因而,实际可考虑在居民中选择一个最大独立团体问题。
构建一个树状图G,居民为树状图G的顶点,居民间的关系为树状图的边界线。
“1”表示两个居民间没有仇敌关系,“0”表示两个居民间有仇敌关系。
这样最大独立团问题就成了图G顶点集的子集的选取问题,可用子集树表示问题的解空间。
设当前考察结点位于解空间树的第i层。
先考虑顶点到要选入独立团中的所有结点都要相连(即无仇敌关系)且任意两个结点都仇敌关系,然后进入左子树进行深度优先遍历,在进入右子树。
2.3算法原理及设计
2.3.1算法原理
具有限界函数的深度优先的方式系统第搜索问题的解的算法称为回溯法。
它可以系统地搜索某一个问题的所有解或任一解。
回溯法是一个既带有系统性又带有跳跃性的搜索算法。
它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。
算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。
如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯。
否则,进入该子树,继续按深度优先的策略进行搜索。
回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。
而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。
它适用于解一些组合数较大的问题。
回溯法搜索解空间树时,通常采用两种策略避免无效搜索,提高回溯法的搜索效率。
其一是用约束函数在扩展结点处剪去不满足约束的子树;
其二是用限界函数剪去得不到最优解的子树。
这两类函数统称为剪枝函数。
问题的解空间:
应用回溯法解问题时,首先应明确定义问题的解空间。
问题的解空间应到少包含问题的一个(最优)解。
运用回溯法解题通常包含以下3个步骤:
(1)针对所给问题,定义问题的解空间;
(2)确定易于搜索的解空间结构;
(3)以深度优先的方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
对于本题来说,回溯法操作步骤如下:
确定易于搜索的解空间结构;
以深度优先方式搜索解空间,并在搜索过程中利用剪枝函数剪去无效的搜索。
(2)无向图G的最大团问题可以看作是图G的顶点集V的子集选取问题。
因此可以用子集树表示问题的解空间。
设当前扩展节点Z位于解空间树的第i层。
在进入左子树前,必须确认从顶点i到已入选的顶点集中每一个顶点都有边相连。
在进入右子树之前,必须确认还有足够多的可选择顶点使得算法有可能在右子树中找到更大的团。
(3)用邻接矩阵表示图G,n为G的居民数,cn存储当前卫队数,bestn存储最大卫队人数。
cn+n-i为进入右子树的上界函数,当cn+n-i<
bestn时,不能在右子树中找到更大的卫队团,利用剪枝函数可将Z的右结点剪去。
2.3.2算法设计
voidBacktrack(inti,inta[20][20])
if(i>
n)
for(intj=1;
=n;
j++)bestx[j]=x[j];
bestn=cn;
return;
intok=1;
i;
if(x[j]&
&
a[i][j]==0)
ok=0;
break;
if(ok)
x[i]=1;
cn++;
Backtrack(i+1,a);
x[i]=0;
cn--;
if(cn+n-i>
bestn)
用回溯法解决部落卫队问题时,以深度优先方式搜索整个解空间,用完全二叉树表示解空间。
剪枝条件为:
当前卫队人数+剩余居民人数<
当前最优解;
得出的解用一个n元向量V=(x1,x2,...,xn)来表示。
2.4算法实现
iostream.h>
stdlib.h>
stdio.h>
classclique{
friendmaxcl