算法分析与设计实验报告 完整版.docx
《算法分析与设计实验报告 完整版.docx》由会员分享,可在线阅读,更多相关《算法分析与设计实验报告 完整版.docx(20页珍藏版)》请在冰豆网上搜索。
![算法分析与设计实验报告 完整版.docx](https://file1.bdocx.com/fileroot1/2023-1/28/2f170c24-9535-47dd-8ebd-3abbb11ff6d5/2f170c24-9535-47dd-8ebd-3abbb11ff6d51.gif)
算法分析与设计实验报告完整版
《算法分析与设计》课程实验
实验报告
专业:
计算机科学与技术
班级:
姓名:
学号:
完成时间:
2009年6月15日
实验一算法实现一
一、实验目的与要求
熟悉C/C++语言的集成开发环境;
通过本实验加深对分治法、贪心算法的理解。
二、实验内容:
掌握分治法、贪心算法的概念和基本思想,并结合具体的问题学习如何用相应策略进行求解的方法。
三、实验题
1.【伪造硬币问题】给你一个装有n个硬币的袋子。
n个硬币中有一个是伪造的。
你的任务是找出这个伪造的硬币。
为了帮助你完成这一任务,将提供一台可用来比较两组硬币重量的仪器,利用这台仪器,可以知道两组硬币的重量是否相同。
试用分治法的思想写出解决问题的算法,并计算其时间复杂度。
2.【找零钱问题】一个小孩买了价值为33美分的糖,并将1美元的钱交给售货员。
售货员希望用数目最少的硬币找给小孩。
假设提供了数目有限的面值为25美分、10美分、5美分、及1美分的硬币。
给出一种找零钱的贪心算法。
四、实验步骤
理解算法思想和问题要求;
编程实现题目要求;
上机输入和调试自己所编的程序;
验证分析实验结果;
整理出实验报告。
五、实验程序
1.伪造硬币问题
源程序:
//c语言实现
#include
#include
#include
#defineN100
#defineN112
//只能判断是否相等的天平
voidsolve(intcoin[],intcount,intfirst,intlast){
if(count==2){
printf("无法判断\n");
return;
}
if(first==last){//只有一个硬币时候
printf("假币的序号为%d,假币的重量为%d\n",first,coin[first]);
}
elseif(last-first==1){//如果只剩下两个硬币(此时count不为)
if(first>0){//不是最开始的硬币
if(coin[first]==coin[0])//如果第first和第个相等,说明first位置不是伪币
solve(coin,count,first+1,last);
else//否则,说明first位置是伪币
solve(coin,count,first,last-1);
}
elseif(lastif(coin[first]==coin[count-1])//如果第first和最后一个相等,说明last位置不是伪币
solve(coin,count,first+1,last);
else//否则,说明first位置是伪币
solve(coin,count,first,last-1);
}
}
elseif(firstinttemp=(last-first+1)/3;//将硬币分为三组
intsum1=0,sum2=0;
for(inti=0;isum1+=coin[first+i];
sum2+=coin[last-i];
}
if(sum1==sum2){//两边的总重相等,在中间,递归
solve(coin,count,first+temp,last-temp);
}
else{//在两边,不在中间
if(sum1==coin[first+temp]*temp){//左边的和中间的相等,在右边,递归
solve(coin,count,last-temp+1,last);
}
else{
solve(coin,count,first,first+temp-1);//右边的和中间的相等,在左边,递归
}
}
}
}
voidmain(){
inti;
intcoin[N];//定义数组coin用来存放硬币重量
for(i=0;icoin[i]=0;//所用硬币初始值为
coin[N1]=1;//第N1个设置为,即伪币
intcnt=N;
printf("硬币个数:
%d\n",cnt);
solve(coin,cnt,0,cnt-1);
}
2找零钱问题
(1)零钱个数无限制的时候:
源程序:
//c语言实现
#include
main(){
intT[]={25,10,5,1};
inta[5];
intmoney,i,j;
printf("输入钱数:
\n");
scanf("%d",&money);
for(i=0;i<4;i++){
a[i]=money/T[i];
money=money%T[i];
}
printf("找钱结果:
\n硬币:
\t");
for(i=0;i<=3;i++){
printf("%d\t|\t",T[i]);
}
printf("\n个数:
\t");
for(i=0;i<=3;i++){
printf("%d\t|\t",a[i]);
}
printf("\n");
return(0);
}
(2)当零钱个数有个数限制的时候:
源程序:
//c语言实现
#include
main(){
intT[]={25,10,5,1};//硬币的面值
inta[5];//用来记录找钱的个数
intcount[]={1,2,10,1000};//各个面值硬币的个数
intmoney,i;
printf("输入钱数:
\n");
scanf("%d",&money);
for(i=0;i<4;i++){
if(money>T[i]*count[i]){//当剩余钱数大于当前硬币总值
a[i]=count[i];//当前硬币个数取现有的最大值
money=money-T[i]*count[i];
}
else{
a[i]=money/T[i];
money=money%T[i];
}
}
printf("找钱结果:
\n硬币:
\t");
for(i=0;i<=3;i++){
printf("%d\t|\t",T[i]);
}
printf("\n\n个数:
\t");
for(i=0;i<=3;i++){
printf("%d\t|\t",a[i]);
}
printf("\n");
return(0);
}
六、实验结果
1伪造硬币问题运行结果:
硬币个数:
100
假币的序号为12,假币的重量为1
截图:
2找零钱问题(1、硬币个数无限制)运行结果:
输入钱数:
67
找钱结果:
硬币:
25|10|5|1|
个数:
2|1|1|2|
截图:
3找零钱问题(2、硬币个数有限制,其中硬币个数限制分别为1,2,10和1000。
)
运行结果:
输入钱数:
123
找钱结果:
硬币:
25|10|5|1|
个数:
1|2|4|2|
截图:
七、实验分析
1、在伪造硬币问题中,由于提供的用来比较硬币重量的仪器只能知道两组硬币的重量是否相同,而不能判断那一边是较重的或者较轻的,所以当硬币个数是2的时候就不能判断伪币的位置。
时间复杂度为O(nlogn)
2、找零钱问题中,可以把问题分为两种问题:
(1)提供了不限数目的面值为25美分、10美分、5美分、及1美分的硬币,在计算的时候不用考虑硬币数目的限制,从硬币的最大面值开始计算,找到最优解。
(2)提供了数目有限的面值为25美分、10美分、5美分、及1美分的硬币,由于硬币的数目有限制,则在解决的时候要考虑是否已经达到硬币数目的最大限制。
实验二算法实现二
一、实验目的与要求
熟悉C/C++语言的集成开发环境;
通过本实验加深对贪心算法、动态规划和回溯算法的理解。
二、实验内容:
掌握贪心算法、动态规划和回溯算法的概念和基本思想,分析并掌握"0-1"背包问题的三种算法,并分析其优缺点。
三、实验题
1."0-1"背包问题的贪心算法
2."0-1"背包问题的动态规划算法
3."0-1"背包问题的回溯算法
四、实验步骤
理解算法思想和问题要求;
编程实现题目要求;
上机输入和调试自己所编的程序;
验证分析实验结果;
整理出实验报告。
五、实验程序
1,"0-1"背包问题的贪心算法
#include
#include
#include
#defineN5//物体个数
intm[10][10];
intv[N];//v[i]为价值
intw[N];//w[i]为重量
intx[N];
intx2[N];
intx1[N];
floats[N];//单位价值
voidSort(float*s){//排序子程序
inti,j,k;
floattemp;
intt;//记录交换时的临时值
for(i=1;i<=N;i++){
x1[i]=i;}
for(i=1;i<=N;i++){
for(j=i+1;j<=N;j++){
if(s[i]
t=x1[j];
x1[j]=x1[i];
x1[i]=t;//记录交换之前的位置
temp=s[i];
s[i]=s[j];
s[j]=temp;
t=w[i];
w[i]=w[j];
w[j]=t;
t=v[i];
v[i]=v[j];
v[j]=t;
}
}
}
}
voidKnapsack(intc,intn){
inti;
Sort(s);
for(i=1;i<=n;i++)
//x[i]=0;
x[x1[i]]=0;
for(i=1;i<=n;i++){
if(w[i]>c)break;
//x[i]=1;
x[x1[i]]=1;
c-=w[i];
}
if(x[i]<=n)x[x[i]]=c/w[i];
}
main(){
inti;
intc;//容量
intn=N;
/*************输入各个数据****************/
printf("请输入%d个物体的价值:
",n);
for(i=1;i<=n;i++)
scanf("%d",&v[i]);
printf("请输入%d个物体的重量:
",n);
for(i=1;i<=n;i++)
scanf("%d",&w[i]);
printf("请输入容量:
");
for(i=1;i<=n;i++)
s[i]=(float)v[i]/(float)w[i];
scanf("%d",&c);
printf("\n物体的单位价值:
\n");
for(i=1;i<=n;i++){
printf("\t%f",s[i]);
}
/************输出结果***************/
printf("\n重量:
");
for(i=1;i<=n;i++){
printf("\t%d",w[i]);
}
printf("\n价值:
");
for(i=1;i<=n;i++){
printf("\t%d",v[i]);
}
Knapsack(c,n);
printf("\n结果:
");
for(i=1;i<=n;i++){
printf("\t%d",x[i]);
}
printf("\n\t(其中表示放进背包)\n");
return(0);
}
2,"0-1"背包问题的动态规划算法
#include
#include
#defineN5//物体个数
intm[10][10];
intv[N];//v[i]为价值
intw[N];//w[i]为重量
intx[N];
intmin(intn1,intn2){
if(n1>n2)
returnn2;
elsereturnn1;
}
intmax(intn1,intn2){
if(n2>n1)
returnn2;
elsereturnn1;
}
voidKnapsack(intc,intn){
inti,j;
intjMax=min(w[n]-1,c);//当前最大容量
for(j=0;j<=jMax;j++)//初始化m
m[n][j]=0;
for(j=w[n];j<=c;j++)//
m[n][j]=v[n];
for(i=n-1;i>1;i--){
jMax=min(w[i]-1,c);
for(j=0;j<=jMax;j++)
m[i][j]=m[i+1][j];
for(j=w[i];j<=c;j++)
m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
}
m[1][c]=m[2][c];
if(c>=w[1])
m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);
}
voidTraceback(intc,intn){
inti;
for(i=1;iif(m[i][c]==m[i+1][c])x[1]=0;
else{
x[i]=1;
c-=w[i];
}
x[n]=(m[n][c])?
1:
0;
}
main(){
inti;
intc;//容量
intn=N;
/*************输入各个数据****************/
printf("请输入%d个物体的价值:
",n);
for(i=1;i<=N;i++)
scanf("%d",&v[i]);
printf("请输入%d个物体的重量:
",n);
for(i=1;i<=N;i++)
scanf("%d",&w[i]);
printf("请输入容量:
");
scanf("%d",&c);
Knapsack(c,n);
Traceback(c,n);
/************输出结果***************/
printf("\n重量:
");
for(i=1;i<=N;i++){
printf("\t%d",w[i]);
}
printf("\n价值:
");
for(i=1;i<=N;i++){
printf("\t%d",v[i]);
}
printf("\n结果:
");
for(i=1;i<=N;i++){
printf("\t%d",x[i]);
}
printf("\n\t(其中表示放进背包)\n");
return(0);
}
3,"0-1"背包问题的回溯算法
源程序:
//c++实现
#include
usingnamespacestd;
classKnap{
friendintKnapsack(intp[],intw[],intc,intn);
public:
voidprint(){
for(intm=1;m<=n;m++){
cout<}
cout<};
private:
intBound(inti);
voidBacktrack(inti);
intc;//背包容量
intn;//物品数
int*w;//物品重量数组
int*p;//物品价值数组
intcw;//当前重量
intcp;//当前价值
intbestp;//当前最优值
int*bestx;//当前最优解
int*x;//当前解
};
intKnap:
:
Bound(inti){
//计算上界
intcleft=c-cw;//剩余容量
intb=cp;
//以物品单位重量价值递减序装入物品
while(i<=n&&w[i]<=cleft){
cleft-=w[i];
b+=p[i];
i++;
}
//装满背包
if(i<=n)
b+=p[i]/w[i]*cleft;
returnb;
}
voidKnap:
:
Backtrack(inti){
if(i>n){
if(bestpprintf("最优解为\n");
for(intj=1;j<=n;j++)
bestx[j]=x[j];
bestp=cp;
}
return;
}
if(cw+w[i]<=c){//搜索左子树
x[i]=1;
cw+=w[i];
cp+=p[i];
Backtrack(i+1);
cw-=w[i];
cp-=p[i];
}
if(Bound(i+1)>bestp){//搜索右子树
x[i]=0;
Backtrack(i+1);
}
}
classObject{
friendintKnapsack(intp[],intw[],intc,intn);
public:
intoperator<=(Objecta)const{
return(d>=a.d);
}
private:
intID;
floatd;
};
intKnapsack(intp[],intw[],intc,intn){
//为Knap:
:
Backtrack初始化
intW=0;
intP=0;
inti=1;
Object*Q=newObject[n];
for(i=1;i<=n;i++){
Q[i-1].ID=i;
Q[i-1].d=1.0*p[i]/w[i];
P+=p[i];
W+=w[i];
}
if(W<=c)
returnP;//装入所有物品
//依物品单位重量价值排序
floatf;
for(i=0;ifor(intj=i;jif(Q[i].df=Q[i].d;
Q[i].d=Q[j].d;
Q[j].d=f;
}
}
KnapK;
K.p=newint[n+1];
K.w=newint[n+1];
K.x=newint[n+1];
K.bestx=newint[n+1];
K.x[0]=0;
K.bestx[0]=0;
for(i=1;i<=n;i++){
K.p[i]=p[Q[i-1].ID];
K.w[i]=w[Q[i-1].ID];
}
K.cp=0;
K.cw=0;
K.c=c;
K.n=n;
K.bestp=0;
//回溯搜索
K.Backtrack
(1);
K.print();
delete[]Q;
delete[]K.w;
delete[]K.p;
returnK.bestp;
}
voidmain(){
int*p;
int*w;
intc=0;
intn=0;
inti=0;
/*************输入各个数据****************/
printf("请输入物品的个数:
");
scanf("%d",&n);
p=newint[n+1];
w=newint[n+1];
p[0]=0;
w[0]=0;
printf("\n请输入物品的价值:
");
for(i=1;i<=n;i++)
scanf("%d",&p[i]);
printf("\n请输入个物品的重量:
");
for(i=1;i<=n;i++)
scanf("%d",&w[i]);
printf("\n请输入背包容量:
");
scanf("%d",&c);
/************输出结果***************/
cout<}
六、实验结果
1、贪心算法运行结果
请输入5个物体的价值:
46931
请输入5个物体的重量:
47325
请输入容量:
12
物体的单位价值:
1.0000000.8571433.0000001.5000000.200000
重量:
47325
价值:
46931
结果:
00110
(其中1表示放进背包)
2、动态规划法运行结果:
请输入5个物体的价值:
34674
请输入5个物体的重量:
34561
请输入容量:
8
重量:
34561
价值:
34674
结果:
00011
(其中1表示放进背包)
3、回溯法运行结果:
请输入物品的个数:
5
请输入物品的价值:
34674
请输入个物品的重量:
34561
请输入背包容量:
8
最优解为
11001
七、实验分析
1,在贪心算法中首先用Sort()要对物品的重量,价值和单位价值按照单位价值由大到小排序,然后用Knapsack()计算最优值,算法的计算时间上界为O(nlogn)。
2,在动态规划法中,用二维数组m[][]来存储m(i,j)的相应值,按照Knapsack计算后,m[1][c]给出所要求的0-1背包问题的最优值。
相应的最优值可以由Traceback计算:
如果m[1][c]=m[2][c],则x[1]=0,否则x[1]=1,当x[1]=0时由m[2][c]继续构造最优解。
当x[1]=1时,由m[2][