printf("请输入要查找的数:
\n");
scanf("%d",&x);
n=Found(a,x,m);
if(n==-1)
printf("查找失败");
else
printf("\n是第%d个\n",n+1);
}
实验二:
回溯算法八皇后问题
1.实验目的
熟练掌握回溯算法。
2.实验内容
以下问题任选一个完成:
0-1背包问题、装载问题、堡垒问题(ZOJ1002)、*翻硬币问题、8皇后问题、素数环问题、迷宫问题、*农场灌溉问题(ZOJ2412)、*求图像的周长(ZOJ1047)、*骨牌矩阵、*字母转换(ZOJ1003)、*踩气球(ZOJ1004)。
8皇后问题:
在一个8×8的棋盘里放置8个皇后,要求这8个皇后两两之间互相都不“冲突”,也就是同一横行、纵行和对角线上不能同时存在皇后。
3.具体设计
回溯算法的几种形式:
a)用回溯算法搜索子集树的一般模式
voidsearch(intm)
{
if(m>n)//递归结束条件
output();//相应的处理(输出结果)
else
{
a[m]=0;//设置状态:
0表示不要该物品
search(m+1);//递归搜索:
继续确定下一个物品
a[m]=1;//设置状态:
1表示要该物品
search(m+1);//递归搜索:
继续确定下一个物品
}
}
b)用回溯算法搜索子集树的一般模式
voidsearch(intm)
{
if(m>n)//递归结束条件
output();//相应的处理(输出结果)
else
for(i=m;i<=n;i++)
{
swap(m,i);//交换a[m]和a[i]
if()
if(canplace(m))//如果m处可放置
search(m+1);//搜索下一层
swpa(m,i);//交换a[m]和a[i](换回来)
}
}
4.实验结果
5.源代码
#include
#include
intm[8][8]={0};//表示棋盘,初始为0,表示未放置皇后
intnum=0;//解数目
//对于棋盘前row-1行已放置好皇后
//检查在第row行、第column列放置一枚皇后是否可行
boolcheck(introw,intcolumn)
{
if(row==1)returntrue;
inti,j;
//纵向只能有一枚皇后
for(i=0;i<=row-2;i++)
{
if(m[i][column-1]==1)returnfalse;
}//左上至右下只能有一枚皇后
i=row-2;
j=i-(row-column);
while(i>=0&&j>=0)
{
if(m[i][j]==1)returnfalse;
i--;
j--;
}//右上至左下只能有一枚皇后
i=row-2;
j=row+column-i-2;
while(i>=0&&j<=7)
{
if(m[i][j]==1)returnfalse;
i--;
j++;
}
returntrue;
}
//当已放置8枚皇后,为可行解时,输出棋盘
voidoutput()
{
inti,j;
num++;
printf("answer%d:
\n",num);
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)printf("%d",m[i][j]);
printf("\n");
}
}
//采用递归函数实现八皇后回溯算法
//该函数求解当棋盘前row-1行已放置好皇后,在第row行放置皇后
voidsolve(introw)
{
intj;
//考虑在第row行的各列放置皇后
for(j=0;j<8;j++)
{
//在其中一列放置皇后
m[row-1][j]=1;
//检查在该列放置皇后是否可行
if(check(row,j+1)==true)
{
//若该列可放置皇后,且该列为最后一列,则找到一可行解,输出
if(row==8)output();
//若该列可放置皇后,则向下一行,继续搜索、求解
elsesolve(row+1);
}
//取出该列的皇后,进行回溯,在其他列放置皇后
m[row-1][j]=0;
}
}
//主函数
intmain()
{
//求解八皇后问题
solve
(1);
return0;
}
实验四动态规划计算矩阵连乘积
1.实验目的
理解动态规划的基本思想,理解动态规划算法的两个基本要素最优子结构性质和子问题的重叠性质。
熟练掌握典型的动态规划问题。
掌握动态规划思想分析问题的一般方法,对较简单的问题能正确分析,设计出动态规划算法,并能快速编程实现。
2.实验内容
编程实现讲过的例题:
最长公共子序列问题、矩阵连乘问题、凸多边形最优三角剖分问题、电路布线问题等。
本实验中的问题,设计出算法并编程实现。
计算矩阵连乘积
在科学计算中经常要计算矩阵的乘积。
矩阵A和B可乘的条件是矩阵A的列数等于矩阵B的行数。
若A是一个p×q的矩阵,B是一个q×r的矩阵,则其乘积C=AB是一个p×r的矩阵。
由该公式知计算C=AB总共需要pqr次的数乘。
其标准计算公式为:
现在的问题是,给定n个矩阵{A1,A2,…,An}。
其中Ai与Ai+1是可乘的,i=1,2,…,n-1。
要求计算出这n个矩阵的连乘积A1A2…An。
递归公式:
3.具体设计
1.分析最优解的结构
设计求解具体问题的动态规划算法的第一步是刻画该问题的最优解的结构特征。
我们将矩阵连乘积AiAi+1....Aj简记为A[i:
j]。
考察计算A[1:
n]的最优计算次序。
设这个计算次序在矩阵Ak和Ak+1之间将矩阵链断开,1<=k以此次序,总的计算量为A[1:
k]的计算量加上A[k+1:
n]的计算量,再加上A[1:
k]和A[k+1:
n]相称的计算量。
这个问题的关键特征是:
计算A[1:
n]的最优次序所包含的计算矩阵子链a[1:
k]和A[k+1:
n]的次序也是最优的。
因此,矩阵连乘积计算次序问题的最优解包含着其子问题的最优解。
这种性质称为最优子结构性质。
问题的最优子结构性质是该问题可以用动态规划算法求解的显著特征。
2.建立递归关系
设计动态规划算法的第二步就是递归地定义最优值。
对于矩阵连乘积的最有计算次序问题,设计算A[i:
j],1<=i<=j<=n,所需的最少数乘次数为m[i][j],则原问题的最优值为m[1][n]。
当i=j时,A[i;j]=Ai,为单一矩阵,无需计算,因此m[i][i]=0。
当i事实上,若计算A[i:
j]的最优次序在Ak和Ak+1之间断开i<=k其中Pi表示第i个矩阵的列数,也是第i-1个矩阵的行数,P0表示第一个矩阵的行数。
由于在计算时并不知道断开点k的位置,所以k还未定。
不过k的位置只有j-i个可能。
从而m[i][j]可以递归地定义为
当i=j:
m[i][j]=0
当im[i][j]=min{m[i][k]+m[k+1][j]+Pi-1*Pk*Pj}
m[i][j]给出了最优值,即计算A[i:
j]所需的最少数乘次数。
同时还确定了计算A[i:
j]的最优次序中的断开位置k,也就是说,对于这个k有:
m[i][j]=m[i[k]+m[k+1][j]+Pi-1*Pk*Pj
若将对应于m[i][j]的断开位置k记为s[i][j],在计算最优值m[i][j]后,可以递归地有s[i][j]构造出相应的最优解。
3.计算最优值
根据计算m[i][j]的递归式,容易写一个递归算法计算m[1][n]。
但是简单地递归将好费指数计算时间。
在递归计算时,许多子问题被重复计算多次。
这也是该问题可以用动态规划算法求解的又一显著特征。
用动态规划算法解决此问题,可依据其递归是以自底向上的方式进行计算。
在计算的过程中,保存以解决的子问题答案。
每个子问题只计算一次,而在后面需要时只要简单查一下,从而避免大量的重复计算。
4.实验结果
5.源代码
#include
intmain()
{
intp[101],i,j,k,r,t,n;
intm[101][101];//为了跟讲解时保持一致数组从1开始
ints[101][101];//记录从第i到第j个矩阵连乘的断开位置
printf("pleaseinputthenumberofthematrixs:
\n");
scanf("%d",&n);
for(i=0;i<=n;i++)
{
printf("pleaseinputtheranks'numberofthe%dmatrix:
\n",i+1);
scanf("%d",&p[i]);//读入p[i]的值(注意:
p[0]到p[n]共n+1项)
}
for(i=1;i<=n;i++)//初始化m[i][i]=0
m[i][i]=0;
for(r=1;rfor(i=1;i{
j=i+r;//j为列
m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];//给m[i][j]赋初值
s[i][j]=i;
for(k=i+1;k{
t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if(t{
m[i][j]=t;//m[i][j]取最小值
s[i][j]=k;
}
}
}
printf("thebestsolutionis%d\n",m[1][n]);
}
总结
通过这几次实验,我发现了自身的不足,比如没有很好的书写习惯,考虑问题不周到,对于各个算法的理解不够深入等。
但在编程的过程中我体验到了一分耕耘一分收获的喜悦;多次调试后程序成功运行了,那时候的欢乐是我以前无法想象的。
果然,学习任何一门课程,只要学得用心,都可以从中体会到学习的快乐。
今后我的进步,想必都是从这一点一点敲入编译器的代码中获得的。
我更加了解了分治与递归、回溯算法、动态规划的内容,对于这些算法有了更加深刻的理解。
在实验中,曾遇到不少困难。
但是通过老师与同学们的帮助都一一解决。
程序有些冗余。
还需提高代码的编写能力。
第三个实验是我感觉最难写的一个,也许是之前没有写过与矩阵运算相关的程序的关系,进度很慢,并且对于动态规划的算法实在是难以下手,最终没有完成,所以实验三在检查前才编写完成。
由于自己的能力有限,数据结构方面出了一些问题,而且时间复杂度比较大,但是对于测试的这种小规模问题还是没有很大问题的,可惜没有很大的实用性。
我还需要继续加强自己的算法方面的知识。