算法分析与设计实验报告.docx
《算法分析与设计实验报告.docx》由会员分享,可在线阅读,更多相关《算法分析与设计实验报告.docx(23页珍藏版)》请在冰豆网上搜索。
![算法分析与设计实验报告.docx](https://file1.bdocx.com/fileroot1/2022-11/30/a5279a7e-41b0-486a-937c-faabf0c72417/a5279a7e-41b0-486a-937c-faabf0c724171.gif)
算法分析与设计实验报告
实验报告
班级:
学号:
姓名:
总成绩:
课程名称:
算法分析与设计实训
实验项目:
1、分治法实验
2、动态规划法实验
3、贪心法实验
4、回溯法实验
5、分枝限界法实验
计算机学院工业中心202实验室
二〇一〇年6月21日
项目序号
1
项目名称
分治法实验
成绩
小标题
找最大值和最小值
1、方法思想
分治法是把规模大的问题,分割成n个形式相同规模一定或不可再分的子问题,递归地解决每个子问题,再把子问题的结果汇总,合并得到原问题的解。
分治法在每一层递归上由三个步骤组成:
(1)划分(divide):
将原问题分解为若干规模较小、相互独立、与原问题形式相同的子问题。
(2)解决(conquer):
若子问题规模较小,则直接求解;否则递归求解各子问题。
(3)合并(combine):
将各子问题的解合并为原问题的解。
2、问题描述
我们将分治策略用于此问题,每次将问题分成大致相等的两部分,分别在这两部分中找出最大值与最小值,再将这两个子问题的解组合成原问题的解,就可得到该问题的分治算法。
3、算法描述
REC-MAXMIN(i,j,fmax,fmin)
1ifi=j
2thenfmax←fmin←A[i]
3ifi=(j-1)
4thenifA[i]>A[j]
5thenfmax←A[i]
6fmin←A[j]
elsefmax←A[j]
8fmin←A[i]
9elsemid←[(i+j)/2]
10REC-MAXMIN(i,mid,gmax,gmin)
11REC-MAXMIN(mid+1,j,hmax,hmin)
12fmax←max{gmax,hmax}
13fmin←min{gmin,hmin}
4、程序清单
#include
voidFZFa(inti,intj,int&max,int&min,inta[])
{
if(i==j)
{
max=a[i];
min=a[j];
}
elseif(i==(j-1))
{
if(a[i]>a[j])
{
max=a[i];
min=a[j];
}
else
{
max=a[j];
min=a[i];
}
}
else
{
intmidd=(i+j)/2;
intmax1=0,min1=0,max2=0,min2=0;
FZFa(i,midd,max1,min1,a);
FZFa(midd+1,j,max2,min2,a);
if(max1>max2)
max=max1;
else
max=max2;
if(min1min=min1;
else
min=min2;
}
}
intmain()
{
intt[]={2,4};
intmax,min;
FZFa(0,1,max,min,t);
cout<<"最大值:
"<cout<<"最小值:
"<return0;
}
5、实验结果(可用文字描述和贴图等方式表现实验结果)
项目序号
2
项目名称
动态规划法实验
成绩
小标题
最长公共子序列
1、方法思想
动态规划算法与分治法类似,其基本思想也是将待求解问题分成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
与分治法不同的是,适用于用动态规划法求解的问题,经分解得到的子问题往往不是互相独立的。
在分治法求解时,有些子问题被重复计算了许多次。
如果能够保存已解决的子问题的答案,而再需要时再找出已求的答案,就可以避免大量重复计算,从而得到多项式时间算法。
为了达到这个目的,可以用一个表来记录所有已解决的子问题的答案。
不过孩子问题以后是否被用到,只要它被计算过,就将其结果填入表中。
这就是动态规划的基本思想。
2、问题描述
最长公共子序列为题:
给定两个序列X={x1,x2,x3……xm}和Y={y1,y2,y3……yn},找出X和Y的最长公共子序列。
3、算法描述
LCSLENGTH(X,Y)
1m←length[X]
2n←length[Y]
3fori←1tom
4dol[i,0]←0
5forj←1ton
6dol[0,j]←0
7fori←1tom
8doforj←1ton
9doifxi=yj
10thenl[i,j]←l[i-1,j-1]+1
b[i,j]←1
12elseifl[i-1,j]←l[i,j-1]
13thenl[i,j]←l[i-1,j]
14b[i,j]←2
15elsel[i,j]←l[i,j-1]
16b[i,j]←3
17returnlandb
4、程序清单
#include
intlcsleng(charx[],chary[],inta[10][10],intn,intm)
{
intc[10][10];
inti,j;
for(i=1;i<=m;i++)
c[i][0]=0;
for(i=1;i<=n;i++)
c[0][i];
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
if(x[i]==y[j])
{
c[i][j]=c[i-1][j-1]+1;
a[i][j]=1;
}
elseif(c[i-1][j]>=c[i][j-1])
{
c[i][j]=c[i-1][j];
a[i][j]=2;
}
else
{
c[i][j]=c[i][j-1];
a[i][j]=3;
}
}
returnc[n][m];
}
voidlcs(inti,intj,charx[],inta[10][10])
{
if(i==0||j==0)
return;
if(a[i][j]==1)
{
lcs(i-1,j-1,x,a);
cout<}
elseif(a[i][j]==2)
lcs(i-1,j,x,a);
else
lcs(i,j-1,x,a);
}
intmain()
{
chara[]="kagajsj";
charb[]="asjofgo";
intt[10][10];
intc=lcsleng(a,b,t,7,7);
cout<lcs(7,7,a,t);
return0;
}
5、实验结果
项目序号
3
项目名称
贪心法
成绩
小标题
活动选择问题
1、方法思想
贪心算法总是做出再当前看来最好的选择,也就是说贪心算法并不是从整体最优考虑,它所做出的选择只是在某种意义上看的局部最优选择。
2、问题描述
活动选择问题(activity-selectionproblem)即若干个具有竞争性的活动要求互斥使用某一公共资源,目标是选择最大的相容活动集合。
假定集合S={a1,a2,…,an}中含有n个希望使用某一资源的活动,这样的资源有教室、某一设备等,它们一次只能由一个活动使用。
每个活动ai有开始时间(starttime)si和完成时间(finishtime)fi,其中,0≤si如果某个活动ai被选中使用资源,则该活动在半开区间(si,fi]这段时间占据资源。
如果活动ai和aj在时间区间(si,fi]和(sj,fj]上不重叠,则称它们是相容的(compatible),即如果si≥fj或者sj≥fj,活动ai和aj是相容的。
活动选择问题是选择最大的相容活动集合。
3、算法描述
RECUR-ACTIVITY-SELECT(s,f,i,j)
1m←i+1
2whilem3dom←m+1
4ifm5thenreturn{am}∪RECUR-ACTIVITY-SELECT(s,f,m,j)
//将m加入集合
6elsereturn¢
4、程序清单
#include
intrecuractivityselect(ints[],intf[],inti,intj)
{
intm=i+1,k=0;
while(mm=m+1;
if(m{
cout<k=1+recuractivityselect(s,f,m,j);
}
returnk;
}
intbudigui(ints[],intf[],intk[],intn)
{
k[1]=1;
inti=1,m,t=2,w=1;
for(m=2;m{
if(s[m]>=f[i])
{
k[t]=m;
t++;
w++;
i=m;
}
}
returnw;
}
intmain()
{
inta[]={0,1,2,3,4,5,6,7,8,9,10,11};
intp[]={0,1,2,0,5,3,5,6,8,8,2,12};
intq[]={0,4,5,6,7,8,9,10,11,12,13,14};
intt[12]={0};
inti,f;
cout<<"活动名称";
for(i=0;i<11;i++)
cout<cout<cout<<"活动开始时间";
for(i=0;i<11;i++)
cout<
cout<cout<<"活动结束时间";
for(i=0;i<11;i++)
cout<cout<cout<<"最大相容活动序列是:
"<<"";
f=recuractivityselect(p,q,0,12);
cout<cout<<"安排活动个数:
"<cout<f=budigui(p,q,t,12);
cout</*for(i=0;i<12;i++)
cout<return0;
}
5、实验结果
项目序号
4
项目名称
回溯法---
成绩
小标题
n皇后问题
1、方法思想
回溯法是一个既带有系统性又带有跳跃性的搜索算法。
它在问题的解空间树中,按深度优先策略,从根节点出发搜索解空间树。
算法搜索至解空间树的任何一结点时,先判断该结点是否包含问题的解。
如果肯定不包含,则跳过对以该结点为根的子树的搜索,逐层向其祖先结点回溯;否则进入该子树,继续按深度优先策略搜索。
2、问题描述
我们给棋盘上的行和列从1到8编号,同时也给皇后从1到8编号。
由于每一个皇后应放在不同的行上,不失一般性,假设皇后i放在第i行上,因此8皇后问题可以表示成8元组(x1,x2,…,x8),其中xi(i=1,2,…,8)表示皇后i所放置的列号。
这种表示法的显式约束条件是Si={1,2,3,4,5,6,7,8},i=1,2,…,8。
在这种情况下,解空间为88个8元组组成,而隐式约束条件是没有两个xi相同(即所有皇后必须在不同列上),且满足不存在两个皇后在同一条对角线上。
加上隐式约束条件,问题的解空间可进一步减小。
此时,解空间大小为8!
,因为所有解都是8元组的一个置换。
图5-4表示了8皇后问题的一个解。
3、算法描述
N-QUEEN(n)
1x1←0//第1个皇后的列位置初始化
2k←1//当前行
3whilek>0do
4x[k]←x[k]+1
//到下一列
5whilex[k]≤n¬PLACE(k)do
6x[k]←x[k]+1
7ifx[k]≤n
//找到一个位置
8thenifk=n
//测试是否为问题的解
9thenoutput(X)
//输出解
10elsek←k+1
//转下一行,即给下一个皇后找位置
11x[k]←0
//初始化当前皇后列取值
12elsek←k-1
//回溯
13return
PLACE(k)
1i←1
2whilei3if(x[i]=x[k]orabs(x[i]-x[k])=abs(i-k)
//同一列或同一对角线有两个皇后
4thenreturn(false)
5i←i+1
6return(true)
4、程序清单
#include
#include
boolplace(intk,intx[])
{
intj;
for(j=1;jif((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))
returnfalse;
returntrue;
}
voidbacktrack(intx[],int&sum,intn)
{
x[1]=0;
intk=1;
while(k>0){
x[k]+=1;
while((x[k]<=n)&&(!
place(k,x)))
x[k]+=1;
if(x[k]<=n)
{
if(k==n)
{
for(inti=1;i<=n;i++)
{
for(intj=1;j<=n;j++)
{
if(j==x[i])
cout<<"○";
else
cout<<"□";
}
cout<}
cout<sum++;
}
else{
k++;
x[k]=0;
}
}
elsek--;
}
}
intmain()
{
intn=4,m,i,sum=0;
intx[5];
for(i=0;i<=n;i++)
x[i]=0;
backtrack(x,sum,n);
cout<return0;
}
5、实验结果
项目序号
5
项目名称
分枝限界法---
成绩
小标题
0-1背包问题
1、方法思想
分枝限界法是广度优先或者按照最大价值(或最小成本)搜索解空间树的过程。
它也是一种系统地搜索问题解的方法。
2、问题描述
某商店有n个物品,第i个物品价值为vi,重量(或称权值)为wi,其中vi和wi为非负数。
背包的容量为W,W为一非负数。
目标是如何选择装入背包的物品,使装入背包的物品总价值最大。
可将这个问题形式描述为
,约束条件为
xi∈{0,1},1≤i≤n
3、算法描述
LUBOUND(v,w,cw,cv,n,k,LBB,UBB)
//cw表示背包可用权值,cv表示已得价值,LBB=-u(X),UBB=-l(X)
1LBB←cv
2c←cw
3fori←ktondo
4ifc5thenUBB←LBB+c(v[i]/w[i])
6forj←i+1tondo
7ifc≥w[j]
8thenc←c-w[i]
9LBB←LBB+v[j]
10return
11c←c-w[i]
12LBB←LBB+v[i]
13UBB←LBB
INSERTNODE(par,lev,t,cap,valu,ub,id)
1GETNODE(Node)//生成一个新结点Node
2Parent(Node)←par
3Level(Node)←lev
4Tag(Node)←t
5CW(Node)←cap
6CV(Node)←valu
7Id(Node)←id
8ADD(Node)
PRINT(Lower,ans,n)
1print(“valueofoptimalsolutionis”,Lower)
2forj←ndownto1do
3ifTag(ans)=1
4thenprint(j)
5ans←Parent(ans)
LCBB(v,w,W,n,ε)
1INIT//初始化可用结点及活结点表
2INSERTNODE(E)//根结点
3Parent(E)←0
4Level(E)←1
5CW(E)←W
6CV(E)←0
7LUBOUND(v,w,W,n,0,1,LBB,UBB)
8Lower←LBB-ε
9UB(E)←UBB
10do
11i←Level(E)
12cap←CW(E)
13valu←CV(E)
14if(i=n+1)//叶结点
15ifvalu>Lower
16thenLower←valu
17ans←E
18elseifcap≥w[i]//左孩子可行
19thenINSERTNODE(E,i+1,1,cap-w[i],valu+v[E],UB[E])
20LUBOUND(v,w,cap,valu,n,i+1,LBB,UBB)//右孩子是否成为活结点
21ifUBB>Lower//判断右孩子是否成为活结点
22thenINSERTNODE(E,i+1,0,cap,valu,UBB)
23Lower←max{Lower,LBB-ε}
24if不存在活结点thenbreak//退出do-while循环
25EXTRACT-MAX(E)//下一个E结点是UB中最大的结点
26while(UB(E)>Lower)
27PRINT(Lower,ans,n)
4、程序清单
#include
#include
#definenum5//物品的个数
intlbb=0,ubb=0;//当前的价值和当前重量
intmaxweight=75;//背包能能容的最大重量
intf=1;
structaa
{
intparent;//该结点的父结点号
intLevel;//结点所在层次
intTag;//该结点是否入列的标志
intCW;//背包剩余空间
intCV;//当前总价值
intUB;//该结点最大下限界
intid;//该结点标记号
};
structaaans[100];
typedefstructqnode
{
aabag[100];
intfront,rear;
}LNode;
voidinitLNode(LNode*&q)
{
q=newLNode;
q->front=q->rear=0;
}
intLNodeEmpty(LNode*q)
{
if(q->rear==q->front)
return1;
else
return0;
}
voidenLNode(LNode*&q,aae)
{
if((q->rear+1)%100==q->front)
{return;cout<<"队满";}
q->rear=(q->rear+1)%100;
q->bag[q->rear]=e;
}
intdeLNode(LNode*&q,aa&e)
{
if(q->rear==q->front)
return0;
q->front=(q->front+1)%100;
e=q->bag[q->front];
return1;
}
LNode*q;
voidinit(aak)
{
k.parent=0;
k.Level=0;
k.Tag=0;
k.CW=0;
k.CV=0;
k.UB=0;
k.id=f;
initLNode(q);
}
voidadd(aat)
{
ans[f]=t;
f++;
enLNode(q,t);
}
voidinsertnode(intpar,intlev,intt,intcap,intvalu,intub,intid)
{
aatp;
tp.parent=par;
tp.Level=lev;
tp.Tag=t;
tp.CW=cap;
tp.CV=valu;
tp.UB=ub;
tp.id=id;
add(tp);
}
voidprint(intlower,aaans[],intn)
{
cout<<"终于做出来了,哈哈!
"<cout<<"背包最大能装的价值是:
"<inttt=f-1;
cout<<"当取得最大价值时装入的物品号:
";
for(intj=n;j>=1;j--)
{
if(ans[tt].Tag==1)
cout<tt=ans[tt].parent;
}
}