算法设计与分析实验报告三篇
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法设计与分析实验报告一
实验名称统计数字问题评分
实验日期2014 年11 月15 日指导教师
姓名专业班级学号
一.实验要求
1、掌握算法的计算复杂性概念。
2、掌握算法渐近复杂性的数学表述。
3、掌握用C++语言描述算法的方法。
4.实现具体的编程与上机实验,验证算法的时间复杂性函数。
二.实验内容
统计数字问题
1、问题描述
一本书的页码从自然数1 开始顺序编码直到自然数n。
书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。
例如,第6 页用数字6 表示,而不是06 或006 等。
数字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,2, (9)
2、编程任务
给定表示书的总页码的10 进制整数n (1≤n≤109) 。
编程计算书的全部页码中分别用到多少次数字0,1,2, (9)
三.程序算法
将页码数除以10,得到一个整数商和余数,商就代表页码数减余数外有多少个1—9作为个位数,余数代表有1—余数本身这么多个数作为剩余的个位数,此外,商还代表1—商本身这些数出现了10次,余数还代表剩余的没有计算的商的大小的数的个数。
把这些结果统计起来即可。
四.程序代码
#include<iostream.h>
int s[10]; //记录0~9出现的次数
int a[10]; //a[i]记录n位数的规律
void sum(int n,int l,int m)
{ if(m==1)
{int zero=1;
for(int i=0;i<=l;i++) //去除前缀0
{ s[0]-=zero;
zero*=10;
} }
if(n<10)
{
for(int i=0;i<=n;i++)
{ s[i]+=1; }
return;
}//位数为1位时,出现次数加1
//位数大于1时的出现次数
for(int t=1;t<=l;t++)//计算规律f(n)=n*10^(n-1)
{m=1;int i;
for(i=1;i<t;i++)
m=m*10;
a[t]=t*m;}
int zero=1;
for(int i=0;i<l;i++)
{ zero*= 10;
} //求出输入数为10的n次方
int yushu=n%zero; //求出最高位以后的数
int zuigao=n/zero; //求出最高位zuigao
for(i=0;i<zuigao;i++)
{ s[i]+=zero;
} //求出0~zuigao-1位的数的出现次数
for(i=0;i<10;i++)
{ s[i]+=zuigao*a[l];
} //求出与余数位数相同的0~zuigao-1位中0~9出现的次数
//如果余数是0,则程序可结束,不为0则补上所缺的0数,和最高位对应所缺的数if(yushu==0) //补上所缺的0数,并且最高位加1
{ s[zuigao]++;
s[0]+=l; }
else
{ i=0;
while((zero/=10)>yushu)
{ i++; }
s[0]+=i*(yushu+1);//补回因作模操作丢失的0
s[zuigao]+=(yushu+1);//补回最高位丢失的数目
sum(yushu,l-i-1,m+1);//处理余位数
}}
void main()
{ int i,m,n,N,l;
cout<<"输入数字要查询的数字:";
cin>>N;
cout<<'\n';
n = N;
for(i=0;n>=10;i++)
{ n/=10; } //求出N的位数n-1
l=i;
sum(N,l,1);
for(i=0; i<10;i++)
{ cout<< "数字"<<i<<"出现了:"<<s[i]<<"次"<<'\n'; }}
五.程序调试中的问题
调试过程,页码出现报错。
六.实验结果
算法设计与分析实验报告二实验名称分治法实现归并排序算法评分
实验日期2014 年11 月26 日指导教师
姓名专业班级学号
一.实验要求
1.了解用分治法求解的问题:当要求解一个输入规模为n,且n的取值相当大的问题时,
如果问题可以分成k个不同子集合,得到k个不同的可独立求解的子问题,其中1<k≤n,而且子问题与原问题性质相同,原问题的解可由这些子问题的解合并得出。
那末,对于这类问题分治法是十分有效的。
2.掌握分治法的一般控制流程。
DanC(p,q)
global n,A[1:n]; integer m,p,q; // 1≤p≤q≤n
if Small(p,q) then return G(p,q);
else m=Divide(p,q); // p≤m<q
return Combine(DanC(p,m),DanC(m+1,q));
endif
end DanC
3.实现典型的分治算法的编程与上机实验,验证算法的时间复杂性函数。
二.实验内容
1.编程实现归并排序算法,程序中加入比较次数的计数功能,输出排序结果和比较次数。
2.输入10组相同的数据,验证排序结果和完成排序的比较次数。
3.与复杂性函数所计算的比较次数比较。
4.用表格列出比较结果。
5.给出文字分析。
三.程序算法
1. 归并排序算法
procedure MERGESORT(low,high)
//A(low;high)是一个全程数组,它含
有high-low+1≥0个待排序的元素//
integer low,high;
if low<high;
then mid←, //求这个集合的分割点//
call MERGESORT(low,mid) //将一个子集合排序//
call MERGESORT(mid+1,high) //将另一个子集合排序
call MERGE(low,mid,high) //归并两个已排序的子集合//
endif
end MERGESORT
归并两个已排序的集合
procedure MERGE(low,mid,high)
//A(low:high)是一个全程数组//
//辅助数组B(low;high)//
integer h,i,j,k;
h←low;i←low;j←mid+1;
while h≤mid and j≤high do //当两个集合都没取尽时// if A(h)≤A(j) then B(i) ←A(h);h←h+1
else B(i) ←A(j);j←j+1
endif
i←i+1
repeat
if h>mid then
for k←j to high do //处理剩余的元素//
B(i) ←A(k);i←i+1
repeat
else for k←h to mid do
B(i) ←A(k);i←i+1
repeat
endif
将已归并的集合复制到A
end MERGE
2. 快速排序算法
QuickSort(p,q)
//将数组A[1:n]中的元素
A[p], A[p+1], , A[q]按不降次序排列,
并假定A[n+1]是一个确定的、且大于
A[1:n]中所有的数。
//
int p,q; global n, A[1:n];
if p<q then
j=Partition(p, q+1); // 划分后j成为划分元素的位置
QuickSort(p,j-1);
QuickSort(j+1,q);
endif
end QuickSort
procedure PARTITION(m,p)
//退出过程时,p带着划分元素所在的下标位置。
//
integer m,p,i;global A(m:p-1)
v←A(m);i←m //A(m)是划分元素//
loop
loop i←i+1 until A(i)≥v repeat //i由左向右移//
loop p←p-1 until A(p)≤v repeat //p由右向左移//
if i<p
then call INTERCHANGE(A(i),A(p)) //A(i)和A(p)换位// else exit
endif
repeat
A(m) ←A(p);A(p) ←v //划分元素在位置p//
End PARTITION
四.程序代码
1.归并排序
#include<iostream.h>
#include<iomanip.h>
#include<stdlib.h>
#include<time.h>
#define M 11
typedef int KeyType;
typedef int ElemType;
struct rec{
KeyType key;
ElemType data; };
typedef rec sqlist[M];
class guibing{
public:
guibing(sqlist b)
{ for(int i=0;i<M;i++)
r[i]=b[i]; }
void output(sqlist r,int n)
{ for(int i=0;i<n;i++)
cout<<setw(4)<<r[i].key;
cout<<endl; }
void xuanze(sqlist b,int m,int n)
{ int i,j,k;
for(i=m;i<n-1;i++)
{ k=i;
for(j=i;j<n;j++)
if(b[k].key>b[j].key) k=j;
if(k!=i)
{ rec temp=b[k];
b[k]=b[i];
b[i]=temp; }
} }
void merge(int l,int m,int h,sqlist r2)
{ xuanze(r,l,m);
xuanze(r,m,h);
output(r,M);
int i,j,k;
k=i=l;
for(j=m;i<m&&j<h;k++)
{ if(r[i].key<=r[j].key)
{ r2[k]=r[i];
i++; }
else
{ r2[k]=r[j];
j++; }
output(r2,M); }
while(j<h)
{ r2[k]=r[j];
j++;
k++; }
while(i<=m)
{ r2[k]=r[i];
i++;
k++; }
output(r2,M); }
private:
sqlist r;
};
void main()
{ cout<<"guibingfa1运行结果:\n";
sqlist a,b;
int i,j=0,k=M/2,n=M;
srand(time(0));
for(i=0;i<M;i++)
{ a[i].key=rand()%80;b[i].key=0; }
guibing gx(a);
cout<<"排序前数组:\n";
gx.output(a,M);
cout<<"数组排序过程演示:\n";
gx.merge(j,k,n,b);
cout<<"排序后数组:\n";
gx.output(b,M);
cin.get(); }
2.快速排序
#include<iostream.h>
#include<iomanip.h>
#include<stdlib.h>
#include<time.h>
#define MAXI 10
typedef int KeyType;
typedef int ElemType;
struct rec{
KeyType key;
ElemType data; };
typedef rec sqlist[MAXI];
class kuaisu
{public:
kuaisu(sqlist a,int m):n(m)
{ for(int i=0;i<n;i++) b[i]=a[i]; } void quicksort(int s,int t)
{ int i;
if(s<t){
i=part(s,t);
quicksort(s,i-1);
quicksort(i+1,t); }
else return; }
int part(int s,int t)
{ int i,j;
rec p;
i=s;j=t;p=b[s];
while(i<j)
{ while(i<j&&b[j].key>=p.key)j--;
b[i]=b[j];
while(i<j&&b[i].key<=p.key)i++;
b[j]=b[i]; }
b[i]=p;
output();
return i; }
void output()
{ for(int i=0;i<n;i++)
cout<<setw(4)<<b[i].key;
cout<<endl; }
private:
sqlist b;
int n;};
void main()
{ cout<<"kuaisu1.cpp运行结果:\n";
sqlist a1;
int i,n=MAXI,low=0,high=9;
srand(time(0));
for(i=0;i<n;i++)
a1[i].key=rand()%80;
kuaisu px(a1,n);
cout<<"数组排序过程演示:\n";
px.quicksort(low,high);
cout<<"排序后数组:\n";
px.output();
cin.get();}
五.程序调试中的问题
调试过程中,在排序方面有问题。
六.实验结果
1.归并排序
2.快速排序
算法设计与分析实验报告三
实验名称动态规划算法实现多段图的最短路径问题评分
实验日期2014 年11 月26 日指导教师
姓名专业班级学号
一.实验要求
1. 理解最优子结构的问题
有一类问题的活动过程可以分成若干个阶段,而且在任一阶段后的行为依赖于该阶段的状态,与该阶段之前的过程如何达到这种状态的方式无关。
最优子结构性质:原问题的最优解包含了其子问题的最优解。
子问题重叠性质:每次产生的子问题并不总是新问题,有些子问题被反复计算多次。
问题的最优子结构性质和子问题重叠性质是采用动态规划算法的两个基本要素。
2.理解分段决策Bellman方程。
每一点最优都是上一点最优加上这段长度。
即当前最优只与上一步有关。
U s 初始值,u j 第j 段的最优值。
3.一般方法
1) 找出最优解的性质,并刻画其结构特征; 2) 递归地定义最优值(写出动态规划方程); 3) 以自底向上的方式计算出最优值;
4) 根据计算最优值时得到的信息,构造一个最优解。
二.实验内容
1.编程实现多段图的最短路径问题的动态规划算法。
2.图的数据结构采用邻接表。
3.要求用文件装入5个多段图数据,编写从文件到邻接表的函数。
4.验证算法的时间复杂性。
三.程序算法
多段图算法:
Procedure FGRAPH (E,k,n,P )
//输入是按段的顺序给结点编号的,有n 个结点的k 段图。
E 是边集,c (i ,j )是边<i ,j>的成本。
P (1:k )是最小成本路径。
//
real COST(n),integer(n-1),P(k),r,j,k,n COST(n)<-0
for j<-n-1 to 1 by -1 do //计算COST (j )// 设r 是一个这样的结点,(j ,r )∈E 且使c (j ,r )+COST (r )取最小值
COST (j )<- c (j ,r )+COST (r );D(j)<-r;Repeat //向前对j-1进行决策// P (1)<-1; P (k )<-n;
for j<-2 to k-1 do // 找路径上的第j 个节点// P (j )<-D(P(j-1));repeat; end FGRAPH
⎪⎩
⎪⎨⎧+==≠}.
{min ,0ij i j
i j s w u u u
四.程序代码
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <iostream.h>
#define MAX 100
#define n 12 /*顶点数*/
#define k 5 /*段数*/
int c[n][n];
void init(int cost[]) //初始化图
{ int i,j;
for(i=0;i<13;i++)
{ for(j=0;j<13;j++)
{ c[i][j]=MAX; } }
c[1][2]=9; c[1][3]=7; c[1][4]=3; c[1][5]=2; c[2][6]=4; c[2][7]=2;
c[2][8]=1;
c[3][6]=2; c[3][7]=7; c[4][8]=11; c[5][7]=11; c[5][8]=8; c[6][9]=6;
c[6][10]=5;
c[7][9]=4; c[7][10]=3; c[8][10]=5; c[8][11]=6; c[9][12]=4;
c[10][12]=2;c[11][12]=5;}
void fgraph(int cost[],int path[],int d[]) //使用向前递推算法求多段图的最短路径{ int r,j,temp,min;
for(j=0;j<=n;j++)
cost[j]=0;
for(j=n-1;j>=1;j--)
{ temp=0;
min=c[j][temp]+cost[temp]; //初始化最小值
for(r=0;r<=n;r++)
{ if(c[j][r]!=MAX)
{ if((c[j][r]+cost[r])<min) //找到最小的r
{ min=c[j][r]+cost[r];
temp=r; }
} }
cost[j]=c[j][temp]+cost[temp];
d[j]=temp; }
path[1]=1;
path[k]=n;
for(j=2;j<k;j++)
path[j]=d[path[j-1]];}
void bgraph(int bcost[],int path1[],int d[])//使用向后递推算法求多段图的最短路径{ int r,j,temp,min;
for(j=0;j<=n;j++)
bcost[j]=0;
for(j=2;j<=n;j++)
{ temp=12;
min=c[temp][j]+bcost[temp]; //初始化最小值
for(r=0;r<=n;r++)
{ if(c[r][j]!=MAX)
{ if((c[r][j]+bcost[r])<min) //找到最小的r
{ min=c[r][j]+bcost[r];
temp=r; } } }
bcost[j]=c[temp][j]+bcost[temp];
d[j]=temp; }
path1[1]=1;
path1[k]=n;
for(int i=4;i>=2;i--)
{ path1[i]=d[path1[i+1]]; }}
void main()
{ int cur=-1;
int cost[13],d[12],bcost[13];
int path[k];
int path1[k];
cout<<"\t\t\t动态规划解多段图问题"<<endl;
cout<<"\n\n";
init(cost);
fgraph(cost,path,d);
cout<<"输出使用向前递推算法后的最短路径:\n\n";
for(int i=1;i<=5;i++)
{ cout<<path[i]<<" ";
}
cout<<"\n";
cout<<endl<<"最短路径为长度:"<<cost[1]<<endl;
cout<<"\n";
cout<<"\n输出使用向后递推算法后的最短路径:\n\n";
bgraph(bcost,path1,d);
for(i=1;i<=5;i++)
{ cout<<path1[i]<<" ";
}
cout<<"\n";
cout<<endl<<"最短路径为长度:"<<bcost[12]<<endl;
cout<<"\n";
}
五.程序调试中的问题
动态规划的思想很容易理解,但当用程序代码实现起来的时候又觉得有点困难,经过我反复的调试操作,发现对于邻接表的程序表达不是很好。
六.实验结果
算法设计与分析实验报告四
实验名称贪心算法实现背包问题评分
实验日期2014 年11 月26 日指导教师
姓名专业班级学号
一.实验要求
1. 优化问题
有n个输入,而它的解就由这n个输入满足某些事先给定的约束条件的某个子集组成,而把满足约束条件的子集称为该问题的可行解。
可行解一般来说是不唯一的。
那些使目
标函数取极值(极大或极小)的可行解,称为最优解。
2.贪心法求优化问题
算法思想:在贪心算法中采用逐步构造最优解的方法。
在每个阶段,都作出一个看上去最优的决策(在一定的标准下)。
决策一旦作出,就不可再更改。
作出贪心决策的依据称为贪心准则(greedy criterion)。
3.一般方法
1)根据题意,选取一种量度标准。
2)按这种量度标准对这n个输入排序
3)依次选择输入量加入部分解中。
如果当前这个输入量的加入,不满足约束条件,则不把此输入加到这部分解中。
procedure GREEDY(A,n) /*贪心法一般控制流程*/
//A(1:n)包含n个输入//
solutions←φ //将解向量solution初始化为空/
for i←1 to n do
x←SELECT(A)
if FEASIBLE(solution,x)
then solutions←UNION(solution,x)
endif
repeat
return(solution)
end GREEDY
4. 实现典型的贪心算法的编程与上机实验,验证算法的时间复杂性函数。
二.实验内容
1. 编程实现背包问题贪心算法。
通过具体算法理解如何通过局部最优实现全局最优,并验
证算法的时间复杂性。
2.输入5个的图的邻接矩阵,程序加入统计prim算法访问图的节点数和边数的语句。
3.将统计数与复杂性函数所计算的比较次数比较,用表格列出比较结果,给出文字分析。
三.程序算法
计算每种物品单位重量的价值,将可能多的单位重量价值最高的物品装入背包,如果单位重量价值最高的物品全部装入背包后,背包的总重量小于C,则选择单位重量次高的物品并尽可能多的装入背包,依次进行下去,直到背包装满为止。
四.程序代码
#include"stdio.h"
void main(void)
{ int C=6;//背包容量6
int n=5;//5个物品
int w[]={3,2,1,4,5};//物品重量
int v[]={25,20,15,40,50};//物品价值
int x[]={0,0,0,0,0};//单位价值初始化
int q[5];
int m,i,j,p,vx,wx,k,ii;
int V=0;//总价值初始化
//计算单位价值
printf("单位价值为:\n");
for(m=0;m<5;m++)
{ q[m]=m;
x[m]=v[m]/w[m];
printf("x[%d]=%d\t",m,x[m]); }
//冒泡排序
for(i=0;i<4;i++)
{ for(j=0;j<4-i;j++)
{ if(x[j]<x[j+1])
{//交换单位价值
p=x[j];
x[j]=x[j+1];
x[j+1]=p;
//交换价值对应位置
vx=v[j];
v[j]=v[j+1];
v[j+1]=vx;
//交换重量对应位置
wx=w[j];
w[j]=w[j+1];
w[j+1]=wx;
//交换商品编号
m=q[j];
q[j]=q[j+1];
q[j+1]=m; } } }
printf("\n单位价值降序为:\n");
for(i=0;i<5;i++)
printf("x[%d]=%d\t",i,x[i]);
//装入背包
for(i=0;i<n&&w[i]<C;i++)
{ if(w[i]<=C)
{ V+=v[i];
C=C-w[i]; } }
k=i;
if(C!=0)
{ V+=v[i]*C/w[i];
C=0; }
for(ii=0;ii<=k;ii++)
{ printf("\n放入第%d个物品:\n物品的重量为:%d\n物品的价值为:%d\n背包剩余容量为:%d\n",q[ii]+1,w[ii],v[ii],C); }
printf("\n总价值为:%d\t",V);
}
五.程序调试中的问题
在调试时,装入背包过程如何保证装入不完整物品,即背包剩余容量不能满足完全放入下一个物品。
六.实验结果。