算法分析与设计试验报告.docx

上传人:b****7 文档编号:10147265 上传时间:2023-02-08 格式:DOCX 页数:16 大小:112.90KB
下载 相关 举报
算法分析与设计试验报告.docx_第1页
第1页 / 共16页
算法分析与设计试验报告.docx_第2页
第2页 / 共16页
算法分析与设计试验报告.docx_第3页
第3页 / 共16页
算法分析与设计试验报告.docx_第4页
第4页 / 共16页
算法分析与设计试验报告.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

算法分析与设计试验报告.docx

《算法分析与设计试验报告.docx》由会员分享,可在线阅读,更多相关《算法分析与设计试验报告.docx(16页珍藏版)》请在冰豆网上搜索。

算法分析与设计试验报告.docx

算法分析与设计试验报告

中南大学

算法分析与设计

实验报告

学院:

_____

专业班级:

学号:

姓名:

指导教师:

2011年12月

实验一

实现求n皇后问题和子集和数问题的回溯算法

<一>n皇后问题

1、设计思想

(1)为解决这个问题,我们把棋盘的横坐标定为i,纵坐标定为j,i和j的取值范围是从1到8。

当某个皇后占了位置(i,j)时,在这个位置的垂直方向、水平方向和斜线方向都不能再放其它皇后了。

(2)为第i个皇后选择位置的算法如下:

for(j=1;j<=8;j++)/*第i个皇后在第j行*/

if((i,j)位置为空))/*即相应的三个数组的对应元素值为1*/

{占用位置(i,j)/*置相应的三个数组对应的元素值为0*/

ifi<8

为i+1个皇后选择合适的位置;

else输出一个解

}

intiStart,iEnd;

iStart=GetTickCount();//得到系统时间

nQueen(n);

iEnd=GetTickCount();//得到系统时间

cout<<"Itneed"<

总而言之,通过这次实验,我更加明白了回溯法的设计思想。

2、源代码:

#include

#include

#include

#include

classQueen{

friendintnQueen(int);

boolPlace(intk);

voidBacktrack(intt);

voidOutput();

intn,//皇后个数

longsum;//当前已找到的可行性方案数

};

boolQueen:

:

Place(intk){

for(intj=1;j

if((abs(k-j)==abs(x[k]-x[j]))||(x[j]==x[k])){

returnfalse;

}

}

returntrue;

}

voidQueen:

:

Backtrack(intt){

if(t>n){

sum++;

Output();

}

else{

for(inti=1;i<=n;i++){

x[t]=i;

if(Place(t)){

Backtrack(t+1);

}

}

}

}

intnQueen(intn){

QueenX;

X.n=n;

X.sum=0;

int*p=newint[n+1];

for(inti=0;i<=n;i++){

p[i]=0;

}

X.x=p;

X.Backtrack

(1);

delete[]p;

returnX.sum;

}

voidQueen:

:

Output(){

cout<<"\n*****第"<

cout<<"┌";//head行

for(intk=1;k

cout<<"--┬";

cout<<"--┐\n";

for(inti=1;i<=n;i++){

cout<<"│";

for(intj=1;j<=x[i]-1;j++)

cout<<"│";

cout<<"⊙",x[i]+1;cout<<"│";

for(intj=x[i];j<=n-1;j++)

cout<<"│";

cout<<"\n";

if(i

cout<<"├";//间行

for(intk=1;k

cout<<"--┼";

cout<<"--┤\n";

}

if(i>n-1){

cout<<"└";//end行

for(intp=1;p

cout<<"--┴";

cout<<"--┘\n";

}

}

cout<

}

intmain(){

intn,m;

cout<<"\n\n请输入皇后的个数:

";

cin>>n;

intiStart,iEnd;

m=nQueen(n);

cout<<"\n***"<

}

运行截图:

 

<二>1、子集和数问题的表示方案

本设计利用大小固定的元组来研究回溯算法,在此情况下,解向量的元素X(i)取1或0值,它表示是否包含了权数W(i).生成图中任一结点的儿子是很容易的。

对于i级上的一个结点,其左儿子对应于X(i)=1,右儿子对应于X(i)=0。

对于限界函数的一种简单选择是,当且仅当

时,B(X

(1),···,X(k))=true。

显然,如果这个条件不满足,X

(1),···,X(k)就不能导致一个答案结点。

如果假定这些W(i)一开始就是按非降次序列排列的,那么这些限界函数可以被强化。

在这种情况下,如果

则X

(1),···,X(k)就不能导致一个答案结点。

因此,将要使用的限界函数是

B

(X

(1),···,X(k))=true,当且仅当

2主要数据类型与变量

intM;//表示要求得到的子集和;

ints;//表示所选当前元素之前所选的元素和;

intw[N];//存储原始集合的N个元素,根据问题实例初始化;

intx[N];//变长表示的解向量,不进行初始化;

3算法或程序模块

#include

#defineM31

#defineN4//集合元素个数

intw[N]={11,13,24,7};

intx[N];

voidSubset(ints,intk){//解子集和数问题函数

inti,l;l=0;x[l]=k;

while(l>=0){

while(s+w[x[l]-1]

s=s+w[x[l]-1];

k++;l++;

x[l]=k;

}

while(s+w[x[l]-1]>M&&k<=N){

k++;x[l]=k;

}

if(s+w[x[l]-1]==M){

k++;

for(i=0;i<=l;i++)

printf("%d",x[i]);//输出变长解向量

printf("\n");

}

while(k>N){//返回上一个节点,实现回溯的主要思想

l--;k=x[l];x[l]=k+1;s=0;

for(i=0;i

s=s+w[x[i]-1];

}

}

}

}

voidmain(){

Subset(0,1);//调用subset(ints,intk)函数

}

结果

<三>实验心得

第一个实验是在别人代码的基础上,结合自己对回溯算法的理解改的。

在最初的时候,遇到了很大的麻烦,毕竟是改的别人的代码,对代码的理解不是很透彻,出现了很多错误,但在同学们的帮助下,通过自己的一个下午加一个晚上的修改,终于调试成功。

这种列式使用大小固定的元组表示所有的解,得出一个问题的解可以有数种表示形式,而这些表示形式都是的所有的解是满足某些约束条件的多元组。

回溯算法通过系统的检索给定问题的解空间来确定问题的解。

这检索可以用这个解空间的树结构来简化。

对于一个给定的解空间,可能有多种树结构。

 

实验二

用动态规划的方法实现0/1背包问题

1.问题描述:

给定n种物品和一背包.物品i的重量是w[i],其价值为u[i],背包的容量为C.如何选择装入背包的物品,使得装入背包中物品的总价值最大。

2.问题分析及实现:

我们可以先几个数组量,分别是weight[i]表示物品i的重量,value[i]表示物品i的价值,result[i]存放结果,即存放0和1,0表示该物品没有被选,1表示该物品被选,m[amount][capacity]表示物品为i,i+1,i+2,...,n,容量为j时,背包的最大价值,则由动态规划的思想可得:

 

3.源代码;

#include

#include

usingnamespacestd;

voidKnapsack(intm[][11],int*v,int*w,intc,intn);

voidTraceback(intm[][11],int*w,intc,intn,int*x);

voidmain()

{

intwight[6]={0,2,2,6,5,4};//物品重量

intvalue[6]={0,6,3,5,4,6};//物品价值

intcapacity=10;//背包容量

intamount=5;//物品数量

intresult[6]={0,0,0,0,0,0};//存放结果

intm[6][11];//m数组:

m[i][j]表示物品为i,i+1,i+2,...,n,容量为j时,背包的最大价值

for(inti=0;i<6;i++){

for(intj=0;j<11;j++){

m[i][j]=0;

}

}

Knapsack(m,value,wight,capacity,amount);//生成m数组Traceback(m,wight,capacity,amount,result);//倒推出结果

cout<<"\n\ndown!

"<

getche();

}

voidKnapsack(intm[][11],int*v,int*w,intc,intn){

intjMax=min(w[n]-1,c);

for(intj=0;j<=jMax;j++)m[n][j]=0;

for(intj=w[n];j<=c;j++)m[n][j]=v[n];

for(inti=n-1;i>1;i--){

intjMax=min(w[i]-1,c);

for(intj=0;j<=jMax;j++)m[i][j]=m[i+1][j];

for(intj=w[i];j<=c;j++)m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);

}

if(c>=w[1])m[1][c]=max(m[2][c],m[2][c-w[1]]+v[1]);

elsem[1][c]=m[2][c];

}

voidTraceback(intm[][11],int*w,intc,intn,int*x){

for(inti=1;i

if(m[i][c]==m[i+1][c])

x[i]=0;

else{

x[i]=1;

c=c-w[i];

}

x[n]=(m[n][c]>0?

1:

0);

}

cout<<"m[1][10]="<

for(inti=1;i<6;i++){

cout<

}

}

测试数据:

N=5,C=10,w={2,2,6,5,4},v={6,3,5,4,6}

测试结果:

m[1][10]=15

选择:

11001

用户结果屏幕:

 

实验三

用分支限界法实现0/1背包问题

1.设计原理

对于每一个物品i,对于该物品只有选与不选2个决策,总共有n个物品,可以顺序依次考虑每个物品,这样就形成了一棵解空间树:

基本思想就是遍历这棵树,以枚举所有情况,最后进行判断,如果重量不超过背包容量,且价值最大的话,该方案就是最后的答案。

2.主代码为:

K.Backtrack

(1);

delete[]Q;

delete[]K.w;

delete[]K.p;

if((fp=fopen("output.txt","w"))==NULL)

{

fprintf(stderr,"Cannotopeninputfile.\n");

exit(0);

}

fprintf(fp,"%d,%d,%d,%d",K.x[4],K.x[1],K.x[2],K.x[3]);

fclose(fp);

cout<<"当前最优装配:

";

cout<

for(i=1;i

{

cout<<""<

}

cout<

}

template

voidKnap:

:

Backtrack(inti)

{

if(i>n){

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);

}

template

TypepKnap:

:

Bound(inti)

{//计算上界

Typewcleft=c-cw;//剩余容量

Typepb=cp;

//以物品单位重量价值递减序装入物品

while(i<=n&&w[i]<=cleft){

cleft-=w[i];

b+=p[i];

i++;

}

//装满背包

if(i<=n)b+=p[i]/w[i]*cleft;

returnb;

运行截图为

实验四

要求:

用深度优化的方法遍历一个图,并判断图中是否有回路存在,如果有,请输出回路

 

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 考试认证 > 财会金融考试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1