算法实验报告Word格式.docx
《算法实验报告Word格式.docx》由会员分享,可在线阅读,更多相关《算法实验报告Word格式.docx(25页珍藏版)》请在冰豆网上搜索。
2.给出源代码及相应的注释。
3.所有的输入和输出都用文件处理。
三.实验内容:
1.实现求n皇后问题和子集和数问题的回溯算法。
2.用动态规划的方法实现0/1背包问题。
3.用分支限界法实现0/1背包问题。
4.用深度优化的方法遍历一个图,并判断图中是否有回路存在,如果有,请输出回路。
四.实验分析:
实验一:
实现求n皇后问题和子集和数问题的回溯算法。
问题说明:
按照国际象棋的规则在N*N的棋盘上放置彼此不受攻击的皇后问题。
数据表示:
用n个数彼此用“,”隔开来表示那个皇后的最后位置,如:
4皇后问题中,最后结果为1,3,0,2,表示第0列的皇后的位置在1,第1列的皇后的位置在3,第2列皇后的位置在0,第4列的皇后的位置在2.n皇后以此类推。
代码如下:
#include"
stdio.h"
stdlib.h"
math.h"
intx[4]={0};
intPlace(intk)//判断第k行当前列是否可以放置皇后
{
for(inti=0;
i<
k;
i++)
{
if(x[i]==x[k]||(abs(x[i]-x[k])-abs(i-k))==0)
{
return0;
}
}
return1;
}
voidNQueens(intk)
x[k]=-1;
while
(1)
{x[k]=x[k]+1;
while((x[k]<
4)&
&
(!
Place(k)))x[k]=x[k]+1;
if(x[k]<
4)
{if(k<
3)NQueens(k+1);
else
{
for(inti=0;
4;
{
printf("
%d,"
x[i]);
}
printf("
\n"
);
}
elsereturn;
intmain(intargc,char*argv[])
NQueens(0);
system("
PAUSE"
实验二:
用动态规划的方法实现0/1背包问题。
给定n种物品和一背包。
物品i的重量是w,其价值是v,背包的容量为C。
求应怎样装入物体使得装入背包中的物体总价值最大。
算法说明:
采用动态规划的方法,将待求解问题分解成若干个子问题,然后从这些子问题的解得到原问题的解。
在该问题中需要决定x1..xn的值。
假设按i=1,2,...,n的次序来确定xi的值。
如果置x1=0,则问题转变为相对于其余物品(即物品2,3,.,n),背包容量仍为c的背包问题。
若置x1=1,问题就变为关于最大背包容量为c-w1的问题。
现设r?
{c,c-w1}为剩余的背包容量。
在第一次决策之后,剩下的问题便是考虑背包容量为r时的决策。
不管x1是0或是1,[x2,.,xn]必须是第一次决策之后的一个最优方案,如果不是,则会有一个更好的方案[y2,.,yn],因而[x1,y2,.,yn]是一个更好的方案。
假设n=3,w=[100,14,10],p=[20,18,15],c=116。
若设x1=1,则在本次决策之后,可用的背包容量为r=116-100=16。
[x2,x3]=[0,1]符合容量限制的条件,所得值为15,但因为[x2,x3]=[1,0]同样符合容量条件且所得值为18,因此[x2,x3]=[0,1]并非最优策略。
即x=[1,0,1]可改进为x=[1,1,0]。
若设x1=0,则对于剩下的两种物品而言,容量限制条件为116。
总之,如果子问题的结果[x2,x3]不是剩余情况下的一个最优解,则[x1,x2,x3]也不会是总体的最优解。
在此问题中,最优决策序列由最优决策子序列组成。
假设f(i,y)表示剩余容量为y,剩余物品为i,i+1,...,n时的最优解的值,即:
利用最优序列由最优子序列构成的结论,可得到f的递归式为:
当j>
=wi时:
f(i,j)=max{f(i+1,j),f(i+1,j-wi)+vi}①式
当0<
=j时:
fn(1,c)是初始时背包问题的最优解。
以本题为例:
若0≤y<10,则f(3,y)=0;
若y≥10,f(3,y)=15。
利用②式,可得f(2,y)=0(0≤y<10);
f(2,y)=15(10≤y<14);
f(2,y)=18(14≤y<24)和f(2,y)=33(y≥24)。
因此最优解f(1,116)=max{f(2,116),f(2,116-w1)+p1}=max{f(2,116),f(2,16)+20}=max{33,38}=38。
现在计算xi值,步骤如下:
若f(1,c)=f(2,c),则x1=0,否则x1=1。
接下来需从剩余容量c-w1中寻求最优解,用f(2,c-w1)表示最优解。
依此类推,可得到所有的xi(i=1.n)值。
在该例中,可得出f(2,116)=33≠f(1,116),所以x1=1。
接着利用返回值38-p1=18计算x2及x3,此时r=116-w1=16,又由f(2,16)=18,得f(3,16)=14≠f(2,16),因此x2=1,此时r=16-w2=2,所以f(3,2)=0,即得x3=0
代码如下;
#include<
cstdlib>
iostream>
usingnamespacestd;
intw[5]={2,2,6,5,4};
intv[5]={6,3,5,4,6};
intlength=5;
intc=10;
intm[5][10];
voidknapsack(int*v,int*w,intc,intm[][10])
intn=length-1;
intjMax=min(w[n]-1,c);
for(intj=0;
j<
=jMax;
j++)
m[n][j]=0;
for(intj=w[n];
=c;
m[n][j]=v[n];
for(inti=n-1;
i>
1;
i--)
jMax=min(w[i]-1,c);
j++)//背包容量没有i物品大,则从i-n选物品装入包的中价值等于从i+1~n
m[i][j]=m[i+1][j];
for(intj=w[i];
m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
//包可以装入i,则分两种情况,一种是装i,一种是不装i,从中选最大
m[1][c]=m[2][c];
if(c>
=w[1])
m[1][c]=max(m[1][c],m[1][c-w[1]]+v[1]);
voidtraceback(intm[][10],int*w,intc,int*x)
n;
if(m[i][c]==m[i+1][c])
x[i]=0;
x[i]=1;
c-=w[i];
}
x[n]=(m[n][c]>
0)?
1:
0;
intmain(intargc,char*argv[])
intx[5];
knapsack(v,w,c,m);
traceback(m,w,c,x);
5;
if(x[i]==1)
printf("
%d"
w[i]);
//printf("
returnEXIT_SUCCESS;
实验三:
用分支限界法实现0/1背包问题。
算法分析:
采用分支限定法,对物品的选取与否构成一棵解树,左子树表示不装入,右表示装入,通过检索问题的解树得出最优解,并用结点上界杀死不符合要求的结点。
代码如下:
iostream"
//子集空间树结点
classbbnode
friendclassKnap;
friendintKnapsack(intp[],intw[],intc,intn,intbestx[]);
private:
bbnode*parent;
//指向父结点的指针
boolLChild;
//左儿子结点标志
};
//对大堆结点
classHeapNode
public:
operatorint()const{returnuprofit;
intuprofit,//结点的价值上界
profit;
//结点所相应的价值
intweight;
//结点所相应的重量
intlevel;
//活结点在子集树种所处的层序号
bbnode*ptr;
//指向活结点在子集树种相应结点的指针
typedefstructHeap
{
intcapacity;
intsize;
HeapNode*Elem;
}Heap,*MaxHeap;
MaxHeapinitH(intmaxElem)
MaxHeapH;
H=(MaxHeap)malloc(sizeof(Heap));
H->
capacity=maxElem;
Elem=(HeapNode*)malloc((maxElem)*sizeof(HeapNode));
size=0;
returnH;
voidInsertH(HeapNodex,MaxHeapH)
inti,sindex=0;