算法分析与设计课设word版本Word格式文档下载.docx
《算法分析与设计课设word版本Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《算法分析与设计课设word版本Word格式文档下载.docx(14页珍藏版)》请在冰豆网上搜索。
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)
(2)递归地定义最优值(写出动态规划方程);
(3)(3)以自底向上的方式计算出最优值;
(4)(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<
stdio.h>
string.h>
stdlib.h>
#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;
=n;
i++){//DP过程
for(j=2;
j<
=k;
j++){
max=0;
for(d=1;
d<
i;
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("
i<
=n;
i++){
for(j=1;
j<
j++){
%ld\t"
m[i][j]);
printf("
leaf[i][j]);
}
//输出分割后的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--;
Dividedsequence:
i=1;
while((--top)>
=0)
tmp=stack[top];
for(;
i<
=tmp;
i++)
{
%d"
data[i]);
"
for(;
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++){
w[i][i]=a[i];
for(j=i+1;
j++)
w[i][j]=w[i][j-1]*10+a[j];
w[i][j]);
}
maxdp(n,k,a);
%ld\n"
m[n][k]);
print_foot(a,n,k);
return0;
5.2最小重量机器问题
/*头文件最小重量机器设计问题.h*/
#ifndefKNAP_H
#defineKNAP_H
#include<
iostream>
fstream>
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<
<
文件"
<
in<
无法打开!
"
endl;
exit
(1);
fin>
>
n>
m>
d;
//初始化部件个数n,供应商数m,价格限制d
w=newint*[n+1];
for(inti=1;
w[i]=newint[m+1];
for(intj=1;
j<
=m;
fin>
w[i][j];
//初始化部件重量
c=newint*[n+1];
c[i]=newint[n+1];
c[i][j];
//初始化部件价格
fin.close();
min=INT_MAX;
//初始化最小重量
plan=newint[n+1];
plan[i]=0;
//初始化选购计划
fout)
out<
~Machine()
if(fout)
fout.close();
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];
e[i]=0;
Search(1,0,0,e);
//第一个零件开始搜索,初始重量和价格是0
Print();
//输出函数
Search(inti,ints,intl,int*e)
if(i==n+1)//选购完毕
if(s<
min&
&
l<
=d)//找到一个更优解
min=s;
//更新重量最小值
for(inti=1;
plan[i]=e[i];
//更新选购计划
return;
if(s>
min)//重量超过min,剪枝
for(intj=1;
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];
Print()
fout<
min<
fout<
plan[i]<
'
;
/*主函数文件test.cpp*/
intmain()
char*in="
input.txt"
//输入文件
char*out="
output.txt"
//输出文件
Machinemachine(in,out);
//文件初始化机器
machine.Solve();
//回溯法求解
六、结果分析
1.
注释:
输入一个三位数,将其分为两段,使这两端乘积最大。
当这个三位数为521时,5与21相乘积最大,为105
2.
总结
算法是编程最终的部分,想要把程序写的好,就要用好的算法。
不同的问题有不同的算法模型,同一个问题也可能有不同的算法描述。
每种算是都有自己的时间复杂度和空间复杂度。
并不是说时间复杂度低或者空间复杂度就是一个好的算法,这要看用来解决什么问题,还编程的环境结合起来评价的。
所以学编程的人应该把算法学好,这样才有利于编程,也有利于想出更好的算法来解决现实中的问题。
参考文献
[1]王晓东.计算机算法设计与分析(第4版).北京.电子工业出版社.2012.2
[2]严蔚敏.数据结构.北京.清华大学出版社.2009
[3]谭浩强.C语言程序设计(第3版).北京.清华大学出版社.2012