算法分析与设计课设.docx
《算法分析与设计课设.docx》由会员分享,可在线阅读,更多相关《算法分析与设计课设.docx(14页珍藏版)》请在冰豆网上搜索。
![算法分析与设计课设.docx](https://file1.bdocx.com/fileroot1/2022-12/13/9612300b-4d54-4c70-ab1f-0dbeb0f41f19/9612300b-4d54-4c70-ab1f-0dbeb0f41f191.gif)
算法分析与设计课设
成绩评定表
学生姓名
班级学号
专业
课程设计题目
动态规划-k乘积问题
回溯法-最小重量机器问题
评
语
组长签字:
成绩
日期
20年月日
课程设计任务书
学院
专业
学生姓名
班级学号
课程设计题目
动态规划-k乘积问题回溯法-最小重量机器问题
实践教学要求与任务:
要求:
1.巩固和加深对基本算法的理解和运用,提高综合运用课程知识进行算法设计与分析的能力。
2.培养学生自学参考书籍,查阅手册、和文献资料的能力。
3.通过实际课程设计,掌握利用动态规划算法、回溯法、分支限界法等算法的基本思想,并能运用这些方法设计算法并编写程序解决实际问题。
4.了解与课程有关的知识,能正确解释和分析实验结果。
任务:
按照算法设计方法和原理,设计算法,编写程序并分析结果,完成如下内容:
1.运用动态规划算法求解k乘积问题。
2.运用回溯法求解最小重量机器问题。
工作计划与进度安排:
第11周:
查阅资料。
掌握算法设计思想,进行算法设计。
第12周:
算法实现,调试程序并进行结果分析。
撰写课程设计报告,验收与答辩。
指导教师:
201年月日
专业负责人:
201年月日
学院教学副院长:
201年月日
摘要
为了满足人们对大数据量信息处理的渴望,为解决各种实际问题,计算机算法学得到了飞速的发展,线性规划、动态规划、贪心策略等一系列运筹学模型纷纷运用到计算机算法学中,产生了解决各种现实问题的有效算法。
虽然设计一个好的求解算法更像是一门艺术而不像是技术,但仍然存在一些行之有效的、能够用于解决许多问题的算法设计方法,你可以使用这些方法来设计算法,并观察这些算法是如何工作的。
一般情况下,为了获得较好的性能,必须对算法进行细致的调整。
但是在某些情况下,算法经过调整之后性能仍无法达到要求,这时就必须寻求另外的方法来求解该问题。
动态规划的基本思想与分治法类似,也是将待求解的问题分解成若干份的子问题,先分别解决好子问题,然后从子问题中得到最终解。
但动态规划中的子问题往往不是相互独立的,而是彼此之间有影响,因为有些子问题可能要重复计算多次,所以利用动态规划使这些子问题只计算一次。
回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有可行的子树都已被搜索遍才结束。
而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。
这就是以深度优先的方式系统地搜索问题解的回溯算法,它适用于解决一些类似n皇后问题等求解方案问题,也可以解决一些最优化问题。
在做题时,有时会遇到这样一类题目,它的问题可以分解,但是又不能得出明确的动态规划或是递归解法,此时可以考虑用回溯法解决此类问题。
回溯法的优点在于其程序结构明确,可读性强,易于理解,而且通过对问题的分析可以大大提高运行效率。
关键词:
算法;动态规划;回溯法;
一、问题描述
1.1k乘积问题
设I是一个n位十进制整数。
如果将I划分为k段,则可得到k个整数。
这k个整数的乘积称为I的一个k乘积,试设计一个算法,对于给定的I和k,求出I的最大k乘积。
1.2最小重量机器问题
设某一机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得。
设wij是从供应商j处购得的部件i的重量,cij是相应的价格。
试设计一个算法,给出总价格不超过c的最小重量机器设计。
二、算法设计
1.对于给定的I和k,计算I的最大k乘积。
2.对于给定的机器部件重量和机器部件价格,计算总价格不超过d的最小重量机器设计。
三、设计原理
3.1动态规划
动态规划的基本思想是将问题分解为若干个小问题,解子问题,然后从子问题得到原问题的解。
设计动态规划法的步骤:
(1)找出最优解的性质,并刻画其结构特征;
(2)递归地定义最优值(写出动态规划方程);
(3)以自底向上的方式计算出最优值;
(4)根据计算最优值时得到的信息,构造一个最优解。
3.2回溯法
回溯法是一个既带有系统性又带有跳跃性的的搜索算法。
它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。
算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。
如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯。
否则,进入该子树,继续按深度优先的策略进行搜索。
回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。
而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。
这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题。
四、问题分析与设计
4.1k乘积问题
1.分析最优解的结构
为了方便起见,设I(s,t)是I的由s位开始的t位数字组成的十进制数,R(i,j)表示I(0,i)的j乘积。
第j段的起始位置为第w位,1<w≤j。
则有如下关系
R(i,j)=R(i,j-1)×I(w,j-w)
要使R(i,j)最大,则R(i,j-1)也是最大,所以最大K乘积问题的最优解包含其子问题的最优解。
2.建立递归关系
设MaxI[i][j]表示I(0,i)的最大j乘积,则原问题的最优值为MaxI[n][k]。
当k=1时,MaxI[n][1]=I(0,n);
当k≠1时,可利用最优子结构性质计算MaxI[n][k], 若计算MaxI[n][k]的第k段的起始位置为第w位,1<w≤j,则有MaxI[n][k]=MaxI[w][k-1]×I(w,n-w)。
由于在计算时并不知道第k段的起始位置w,所以w还未定。
不过w的值只有n-k+2种可能,即k-1≤w≤n。
所以MaxI[n][k]可以递归地定义为
I(0,n) k=1
MaxI[n][k]=max MaxI[w][k-1]×I(w,n-w) k≠1
MaxI[n][k]给出了最优值,同时还确定了计算最优的断开位置w,也就时说,对于这个w有 MaxI[n][k]=MaxI[w][k-1]×I(w,n-w)
若将对应于MaxI[n][k]的断开位置w记为demarcation[n][k]后,可递归地由 demarcation[n][k]构造相应的最优解。
4.2最小重量机器设计问题
1.用递归函数backtrack(i)来实现回溯法搜索排列树(形式参数i表示递归深度)。
①若cp>d,则为不可行解,剪去相应子树,返回到i-1层继续执行。
②若cw>=weight,则不是最优解,剪去相应子树,返回到i-1层继续执行。
③若i>n,则算法搜索到一个叶结点,用weight对最优解进行记录,返回到i-1层继续执行;
4用for循环对部件i从m个不同的供应商购得的情况进行选择(1≤j≤m)。
2.主函数调用一次backtrack
(1)即可完成整个回溯搜索过程,最终得到的weight即为所求最小总重量,p为该机器最小重量的价格。
五、算法实现
5.1k乘积问题
#include
#include
#include
#defineMAXN51
#defineMAXK10
//m[i][j]表示1~i十进制位分成j段所得的最大乘积
longm[MAXK][MAXN]={{0,0}};
//w[i][j]表示i~j十进制位所组成的十进制数
longw[MAXN][MAXN]={{0,0}};
intleaf[MAXN][MAXN]={{0,0}};
voidmaxdp(intn,intk,int*a)
{
inti,j,d;
longtemp,max;
for(i=1;i<=n;i++){//分成一段
m[i][1]=w[1][i];
}
for(i=2;i<=n;i++){//DP过程
for(j=2;j<=k;j++){
max=0;
for(d=1;d
//Testprintf("%d*%d=%ld\t-----------",m[d][j-1],w[d+1][i],m[d][j-1]*w[d+1][i]);
if((temp=m[d][j-1]*w[d+1][i])>max){
max=temp;
leaf[i][j]=d;
}
}
m[i][j]=max;
printf("\n");
}
}
printf("\n");
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
printf("%ld\t",m[i][j]);
}
printf("\n");
}
printf("\n");
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
printf("%ld\t",leaf[i][j]);
}
printf("\n");
}
}
//输出分割后的K个数
voidprint_foot(int*data,intn,intk)
{
intd,i;
intstack[256];
inttop=0;
inttmp;
tmp=n;
while((tmp=leaf[tmp][k])>0)
{
stack[top++]=tmp;
k--;
}
printf("Dividedsequence:
\n");
i=1;
while((--top)>=0)
{
tmp=stack[top];
for(;i<=tmp;i++)
{
printf("%d",data[i]);
}
printf("");
}
for(;i<=n;i++)
{
printf("%d",data[i]);
}
printf("\n");
}
intmain(void)
{
intn,k,i,j;
inta[MAXN]={0},la=0;
charc;
scanf("%d%d",&n,&k);//inputn,k
while((c=getchar())!
='#'){//readinteger
a[++la]=c-'0';
}
for(i=1;i<=n;i++){
w[i][i]=a[i];
for(j=i+1;j<=n;j++)
w[i][j]=w[i][j-1]*10+a[j];
}
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
printf("%ld\t",w[i][j]);
}
printf("\n");
}
maxdp(n,k,a);
printf("%ld\n",m[n][k]);
print_foot(a,n,k);
return0;
}
5.2最小重量机器问题
/*头文件最小重量机器设计问题.h*/
#ifndefKNAP_H
#defineKNAP_H
#include
#include
usingnamespacestd;
classMachine//机器类
{
public:
Machine(char*in,char*out);//构造函数
~Machine();//析构函数
voidSolve();//输出结果到文件
protected:
voidSearch(inti,ints,intl,int*e);//从第i个部件开始递归搜索
voidPrint();//输出结果
private:
intn;//部件个数
intm;//供应商个数
intd;//价格上限
int**w;//部件重量
int**c;//部件价格
intmin;//最小重量
int*plan;//选购的部件
ofstreamfout;//输出结果文件
};
#endif
/*函数实现文件最小重量机器设计问题.cpp*/
#include"最小重量机器设计问题.h"
Machine:
:
Machine(char*in,char*out):
fout(out)
{
ifstreamfin(in);
if(!
fin)
{
cerr<<"文件"<"<exit
(1);
}
fin>>n>>m>>d;//初始化部件个数n,供应商数m,价格限制d
w=newint*[n+1];
for(inti=1;i<=n;i++)
{
w[i]=newint[m+1];
for(intj=1;j<=m;j++)
fin>>w[i][j];//初始化部件重量
}
c=newint*[n+1];
for(inti=1;i<=n;i++)
{
c[i]=newint[n+1];
for(intj=1;j<=m;j++)
fin>>c[i][j];//初始化部件价格
}
fin.close();
min=INT_MAX;//初始化最小重量
plan=newint[n+1];
for(inti=1;i<=n;i++)
plan[i]=0;//初始化选购计划
if(!
fout)
{
cerr<<"文件"<"<exit
(1);
}
}
Machine:
:
~Machine()
{
if(fout)
fout.close();
for(inti=1;i<=n;i++)
{
if(w[i])
delete[]w[i];
if(c[i])
delete[]c[i];
}
if(w)
delete[]w;
if(c)
delete[]c;
}
voidMachine:
:
Solve()
{
int*e;
e=newint[n+1];
for(inti=1;i<=n;i++)
e[i]=0;
Search(1,0,0,e);//第一个零件开始搜索,初始重量和价格是0
Print();//输出函数
}
voidMachine:
:
Search(inti,ints,intl,int*e)
{
if(i==n+1)//选购完毕
{
if(s{
min=s;//更新重量最小值
for(inti=1;i<=n;i++)
plan[i]=e[i];//更新选购计划
}
return;
}
if(s>min)//重量超过min,剪枝
return;
for(intj=1;j<=m;j++)
{
e[i]=j;
s+=w[i][j];//加上第i部件由j供应商提供的重量
l+=c[i][j];//加上第i部件由j供应商提供的价格
Search(i+1,s,l,e);//递归选购下一个部件
s-=w[i][j];
l-=c[i][j];
}
}
voidMachine:
:
Print()
{
fout<for(inti=1;i<=n;i++)
fout<}
/*主函数文件test.cpp*/
#include"最小重量机器设计问题.h"
intmain()
{
char*in="input.txt";//输入文件
char*out="output.txt";//输出文件
Machinemachine(in,out);//文件初始化机器
machine.Solve();//回溯法求解
return0;
}
六、结果分析
1.
注释:
输入一个三位数,将其分为两段,使这两端乘积最大。
当这个三位数为521时,5与21相乘积最大,为105
2.
总结
算法是编程最终的部分,想要把程序写的好,就要用好的算法。
不同的问题有不同的算法模型,同一个问题也可能有不同的算法描述。
每种算是都有自己的时间复杂度和空间复杂度。
并不是说时间复杂度低或者空间复杂度就是一个好的算法,这要看用来解决什么问题,还编程的环境结合起来评价的。
所以学编程的人应该把算法学好,这样才有利于编程,也有利于想出更好的算法来解决现实中的问题。
参考文献
[1]王晓东.计算机算法设计与分析(第4版).北京.电子工业出版社.2012.2
[2]严蔚敏.数据结构.北京.清华大学出版社.2009
[3]谭浩强.C语言程序设计(第3版).北京.清华大学出版社.2012