算法设计与分析报告大作业
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法分析与设计大作业
班级: 12信科
姓名:郭倩南
学号: 1242155105
完成日期: 2015-6-4
指导教师:陈平
序号选定题目所用算法设计技术
1数字三角形问题动态规划
2集合划分问题分治法
回溯法
3
求子集问题
评分:
大作业报告
1、数字三角形问题
一、问题描述
对于给定的由n行数字组成的数字三角形,计算从三角形的底至顶的路径经过的数字和的最大值。
如:7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
二、实验内容与实验步骤
实验内容:
输入数据的第1 行是数字三角形的行数n,1<=n<=100。
接下来n行是数字三角形各行中的数字。
所有数字在0..99之间
实验步骤:
1、首先证明该问题满足最优化原理
最优化原理:一个最优化策略具有这样的性质,不论过去状态和决策如何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略。
简而言之,一个最优化策略的子策略总是最优的。
2、建立动态规划函数
3、填表
三、实验环境
Window7系统,vc++6.0软件
四、问题分析
由观察数字三角形可知,从数字三角形的顶层出发,下一层选择向左还是向右取决于两个4层数字三角形的最大数字和,而对于第四层的决定取决于第三层的最大数字和,依次类推,可知该问题是多阶段决策最优化问题,并且划分出来的子问题是相互重叠的,所以该问题采用动态规划法解决
动态规划:与分治法相似,把问题分解按层次分成子问题,直到可以直接求解的子问题,然后一级一级地向上求解。
与分治法的出别在于:动态规划适用有许多重复子问题出现的问题,它保存已求出问题的解。
7
3 8 3 8
8 1 0 8 1 1 0
2 7 4 4 2 7 4 7 4 4 4 5 2 6 5 4 5 2 6 5 2 6 5
一个五层数字三角形子问题〔1〕子问题〔2〕
五、问题解决
〔1〕根据对问题的分析,写出解决方法。
1、证明:S,S1,S2,..Sn,t是从S到t的一条数字和最大的路径,从源点S开始,设从S到下一段的顶点S1已经求出,如此问题转化为求从S1到t的数字和最大的路径,显然S1,S2,...Sn,t一定构成一条从S1到t的数字和最大值的路径,如假如不然,设S1,r1,r2,....rq,t是一条数字和最大的路径,如此S,S1,
r1,r2,....rq,t的路径经过数字和的最大值比S,S1,S2,...Sn,t的路径数字和更大,从而导致矛盾,所以数字三角形问题满足最优性原理。
2、动态规划函数:
a[i][j]+=a[i+1][j] 当 a[i+1][j]>a[i+1][j+1] 时
a[i][j]+=a[i+1][j+1] 当a[i+1][j]<=a[i+1][j+1] 时
3、填表
(2)你在调试过程中发现了怎样的问题?又做了怎样的改良?
答:〔a〕在代码编译成功后,显示屏上无任何提示语,让人有点不知所措,感觉设计的不太人性化,于是在代码中又添加了一些提示语句,使其更容易理解和操作
〔b〕算法设计比拟简单,运行结果没有显示路径,所以还有待研究
(3)描述你在进展实现时,主要的函数或操作内部的主要算法;分析这个算法的时、空复杂度
答:主要算法:
int func()
{
int i,j;
for(i=n-1;i>=1;i--)
for(j=1;j<=i;j++)
{
if(a[i+1][j]>a[i+1][j+1]) a[i][j]+=a[i+1][j];
else a[i][j]+=a[i+1][j+1];
}
return a[1][1];
}
该段代码是程序的核心局部,可以根据此代码进展填表。
算法复杂度:O(T(n)∈O(n^2))
六、实验结果总结
七、附录与源程序
#include <iostream>
using namespace std;
const int M=100;
int n;
int a[M][M];
int func()
{
int i,j;
for(i=n-1;i>=1;i--)
for(j=1;j<=i;j++)
{
if(a[i+1][j]>a[i+1][j+1]) a[i][j]+=a[i+1][j];
else a[i][j]+=a[i+1][j+1];
}
return a[1][1];
}
int main()
{
int i,j,max;
cout<<"请输入行数:";
cin>>n;
cout<<"请输入数字三角形:\n";
for(i=1;i<=n;i++)
for(j=1;j<=i;j++)
cin>>a[i][j];
max=func();
cout<<"最大值为"<<max<<endl;
return 0;
}
实验参考的资料
【1】C++面向对象程序设计清华大学
【2】算法分析与设计〔第二版〕清华大学
2、集合划分问题
一、问题描述
给定正整数n,计算出n个元素的集合{1,2,…,n}可以划分为多少个不同的非空子集。
二、实验内容与实验步骤
n个元素的集合{1,2,…,n}可以划分为假如干非空子集。
例如,当n=3时,集合{1,2,3,4}可以划分为5个不同的非空子集。
三、实验环境
四、问题分析
分析要解决的问题,给出你的思路,可以借助图表等辅助表达
答:该问题采用的是分治法解决的,即将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题性质一样。
求出子问题的解,就可得到原问题的解
分治法的求解过程由三个阶段组成:1、划分 2、求解子问题3、合并
通过大量实践发现,在用分治法设计算法时,最好使子问题的规模大致一样。
五、问题解决
〔1〕根据对问题的分析,写出解决方法。
本算法实现采用分治法思想,f(n,m)=f(n-1,m-1)+m*f(n-1,m),设n个元素的集合可以划分为f(n,m)个不同的由m个非空子集组成的集合。
如果求3个元素的集合能够划分多少非空子集,可将问题分解为求两个元素的集合划分问题,进而分解为一个元素的集合划分问题,显然一个元素的集合只能划分成一个非空子集,而f〔2,1〕如此代表两个元素分解成一个非空子集的个数,即{1,2},所以求得f〔2,1〕为1,进而根据递归关系式得到2个元素的的集合划分情况,同理得到3个元素的集合划分情况。
〔2〕主要算法
int pute_bell(int row,int position)
{
if(row==1)
return 1;
if(row == 2 && position ==1)
return 1;
else
{
if(position == 1)
return pute_bell(row-1,row-1);
else
return pute_bell(row,position-1)+ pute_bell(row-1,position-1);
}
}
六、实验结果总结
7、附录与源程序
#include <iostream>
using namespace std;
int pute_bell(int row,int position)
{
if(row==1)
return 1;
if(row == 2 && position ==1)
return 1;
else
{
if(position == 1)
return pute_bell(row-1,row-1);
else
return pute_bell(row,position-1)+ pute_bell(row-1,position-1);
}
}
int main(){
int n=0;
int sum;
cout<<"please input a number."<<endl; cin>>n;
sum=pute_bell(n,n);
cout<<"the resule is "<<sum<<endl;
}
3、求子集问题
一、问题描述
给定一个正整数集合X={x
1,x
2
,…, x
n
}和一个正整数y,设计回溯算法,求集合X
的一个子集Y,使得Y中元素之和等于y
二、实验内容与实验步骤
对于给定集合x[N]={2,1,3,4,2}和正整数12,用回溯算法求得其子集,使子集中元素之和等12,并且记录搜索到第几个元素
三、实验环境
四、问题分析
该问题为求子集问题。
解分量的和小于y为剪枝函数。
当搜索到结点,并且解分量的和等于y时,找到问题的解。
五、问题解决
1.x={x1,x2,x3……xn },sum=0,y={ }为解向量,初始化为全0;
2.k=0;
3.while (k>=0)
y[k]=y[k]-1;
3.2 如果((y[k]==1||y[k]==0)&&k<N)
3.2.1 sum=sum+(y[k]?x[k]:0);
3.2.2 如果(sum==y){break;},找到解,到步骤4
3.2.3 否如此
3.2.3.1 如果(sum<n){k++;},搜索下一个
3.2.3.2 否如此 sum=sum-(y[k]?x[k]:0);
3.3 否如此回溯
3.3.1 sum=sum-(y[k]?x[k]:0);
y[k]=2;
k--;
sum=sum-(y[k]?x[k]:0);
六、实验结果总结
七、附录与源程序
#include <iostream.h>
const int N=5;
int f(int x[],int y[],int n)
{
//初始化y,y为所求的集合
for(int i=0;i<N;i++)
y[i]=2;
int k=0;
int sum=0;
while(k>=0)
{
y[k]=y[k]-1;
if((y[k]==1||y[k]==0)&&k<N){
sum=sum+(y[k]?x[k]:0);
if(sum==n){break;}//找到解
else{
if(sum<n){k++;}//搜索下一个 else{
sum=sum-(y[k]?x[k]:0); }
}
}
else{//回溯
// sum=sum-(y[k]?x[k]:0);
y[k]=2;
k--;
sum=sum-(y[k]?x[k]:0);
}
}
return k;
}
void main()
{
int x[N]={2,1,3,4,2};
int y[N]; //解向量
int n=12; //题目要求等于的和
int k=f(x,y,n);//k表示搜索到第几个元素 cout<<"搜索到第"<<k<<"个元素"<<endl; cout<<"求得子集Y为:\n";
for(int i=0;i<N;i++)
cout<<(y[i]==1?x[i]:0)<<endl;
}
实验参考的资料
【1】C++面向对象程序设计清华大学
【2】算法分析与设计〔第二版〕清华大学。