fmax←A[j];fmin←A[i]
elsefmax←A[i];fmin←A[j]
else:
mid←(i+j)/2/*分成两部分*/
MAXMIN(i,mid,max1,min1)
MAXMIN(mid+1,j,max2,min2)
fmax←max(max1,max2)
fmin←min(min1,min2)
}
如果MAX1和MIN1是I1中的最大和最小元素,MAX2和MIN2是I2中的最大和最小元素,MAX1和MAX2中的大者就是I中的最大元素MAX,MIN1和MIN2中的小者是I中的最小元素MIN。
如果I只包含一个元素,则不需要作任何分割直接就可得到其解。
实验代码如下:
#include"stdio.h"
#defineN100
voidmaxmin2(intA[],inti,intj,int*max,int*min)
{
intmid,max1,max2,min1,min2;
if(j==i)
{*max=*min=A[i]=A[j];
return;
}
if(j-1==i)
{
if(A[i]>A[j])
{
*max=A[i];
*min=A[j];
}
else
{
*max=A[j];
*min=A[i];
}
return;
}
mid=(i+j)/2;
maxmin2(A,mid+1,j,&max2,&min2);
maxmin2(A,i,mid,&max1,&min1);
if(max1>max2)
*max=max1;
else
*max=max2;
if(min1>min2)
*min=min2;
else
*min=min1;
}
main()
{
inti,n;
intA[N];
intmax,min;
printf("请输入要比较的数据的个数:
");
scanf("%d",&n);
for(i=0;i{
printf("请输入第%d个数",i+1);
scanf("%d",&A[i]);
}
maxmin2(A,0,n-1,&max,&min);
printf("最大值为:
%d最小值为:
%d",max,min);
}
运行结果如下图所示:
实验收获与体会:
通过该实验对分治法掌握的更加透彻,明白了分治法发挥的作用。
动态规划实验
对于一个多阶段过程问题,是否可以分段实现最优决策,信赖于该问题是否有最优子结构性质,能否采用动态规划的方法,还要看该问题的子问题是否具有重叠性质。
最优子结构性质:
原问题的最优解包含了其子问题的最优解
子问题的重叠性质:
每次产生的子问题并不总是新问题,有些子问题被反复计算多次。
问题的最优子结构性质和子问题重叠性质是采用动态规划算法的两个基本要素
动态规划一般方法
1.找出最优解的性质,并刻画其结构特征
2.递归地定义最优值(写出动态规划方程)
3.以自底向上的方式计算出最优值
多段图
多段图算法:
ProcedureFGRAPH(E,k,n,P)
//输入是按段的顺序给结点编号的,有n个结点的k段图。
E是边集,c(i,j)是边的成本。
P(1:
k)是最小成本路径。
//
realCOST(n),integer(n-1),P(k),r,j,k,n
COST(n)<-0
forj<-n-1to1by-1do//计算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;
forj<-2tok-1do//找路径上的第j个节点//
P(j)<-D(P(j-1));repeat;
endFGRAPH
实验代码如下:
#include
usingnamespacestd;
#defineMAX100
#definen12//图的总顶点数
#definek5//图的段数
intc[n][n];
voidinit(intcost[])//初始化图
{
inti,j;
for(i=0;i<13;i++)
{
for(j=0;j<13;j++)
{
c[i][j]=MAX;//初始化每条边长度为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;
//给每条边赋值
}
voidfront(intcost[],intpath[],intd[])//向前递推算法求多段图的最短路径
{
intr,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=c[j][r]+cost[r];
temp=r;
}
}
}
cost[j]=c[j][temp]+cost[temp];
d[j]=temp;
}//向前对j-1进行决策
path[1]=1;//第一段所取节点
path[k]=n;//最后一段所取节点
for(j=2;jpath[j]=d[path[j-1]];//找到路径上第j个节点
}
voidback(intbcost[],intpath1[],intd[])//使用向后递推算法求多段图的最短路径
{
intr,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=c[r][j]+bcost[r];
temp=r;
}
}
}
bcost[j]=c[temp][j]+bcost[temp];
d[j]=temp;
}
path1[1]=1;
path1[k]=n;
for(inti=4;i>=2;i--)
{
path1[i]=d[path1[i+1]];
}//找出各段的节点
}
intmain()
{
intcur=-1;
intj;
intcost[13],d[12],bcost[13];
intpath[k];
intpath1[k];
cout<<"\t\t\t\t多段图问题"<cout<<"\n\n";
init(cost);
front(cost,path,d);
cout<<"向前递推算法求得的最短路径:
\n\n";
for(inti=1;i<=5;i++)
{
if(i==5)
cout<else
cout<";
}
cout<<"\n";
cout<"<cout<<"\n";
cout<<"向后递推算法求得的最短路径:
\n\n";
back(bcost,path1,d);
for(j=1;j<=5;j++)
{
if(j==5)
cout<else
cout<";
}
cout<<"\n";
cout<"<cout<<"\n";
}
运行结果如下图所示:
实验收获与体会:
通过多段图实验对动态规划的思想有了更深理解,动态规划与分治法类似,基本思想也是将待求解问题分成若干个子问题,但是分解得到的子问题往往不是互相独立的。
回溯法实验
回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。
算法搜索至解空间树的任意一点时,先判断该结点是否满足约束。
如果不满足,则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。
N皇后:
基本思想:
(1)针对所给问题,定义问题的解空间,使N个皇后不在同行同列,对角线上;
(2)确定易于搜索的解空间结构;
(3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
实验代码如下:
#include
#include"math.h"
classQUEEN
{
public:
friendintnQueen(int);
private:
boolPlace(intk);
voidBacktrack(intt);
intn,*x;
longsum;
};
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;
}
boolQUEEN:
:
Place(intk)
{
for(intj=1;jif((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))
returnfalse;
returntrue;
}
voidQUEEN:
:
Backtrack(intt)
{
if(t>n){sum++;
cout<<"n皇后问题的第"<"<for(t=1;t<=n;t++)
cout<<"("<cout<<"********"<else
for(inti=1;i<=n;i++)
{
x[t]=i;
if(Place(t))
Backtrack(t+1);//递归求解
}
}
intmain()
{intn;
cout<<"***************N皇后问题***************"<cout<cout<<"请输入皇后的个数n:
"<cin>>n;
cout<cout<<"***************N皇后问题结束*************"<}
运行结果如下图所示:
实验收获与体会:
通过该实验对回溯法的思想有了较深的了解,通过亲手实践,加深了记忆与理解,该实验的算法也可以用在类似有关回溯法问题上。