算法设计与分析报告
学生姓名
学号
专业班级
指导教师
完成时间
目录
一、课程内容 (3)
二、算法分析 (3)
1、分治法 (3)
(1)分治法核心思想 (3)
(2)MaxMin算法分析 (3)
2、动态规划 (4)
(1)动态规划核心思想 (4)
(2)矩阵连乘算法分析 (5)
3、贪心法 (5)
(1)贪心法核心思想 (5)
(2)背包问题算法分析 (6)
(3)装载问题算法分析 (7)
4、回溯法 (7)
(1)回溯法核心思想 (7)
(2)N皇后问题非递归算法分析 (7)
(3)N皇后问题递归算法分析 (8)
三、例子说明 (9)
1、MaxMin问题 (9)
2、矩阵连乘 (10)
3、背包问题 (10)
4、最优装载 (10)
5、N皇后问题(非递归) (11)
6、N皇后问题(递归) (11)
四、心得体会 (12)
五、算法对应的例子代码 (12)
1、求最大值最小值 (12)
2、矩阵连乘问题 (13)
3、背包问题 (15)
4、装载问题 (17)
5、N皇后问题(非递归) (19)
6、N皇后问题(递归) (20)
一、课程内容
1、分治法,求最大值最小值,maxmin算法;
2、动态规划,矩阵连乘,求最少连乘次数;
3、贪心法,1)背包问题,2)装载问题;
4、回溯法,N皇后问题的循环结构算法和递归结构算法。
二、算法分析
1、分治法
(1)分治法核心思想
当要求解一个输入规模为n,且n的取值相当大的问题时,直接求解往往是非常困难的。如果问题可以将n个输入分成k个不同子集合,得到k个不同的可独立求解的子问题,其中1 那末,这类问题可以用分治法求解。 分治法的核心技术 1)子问题的划分技术. 2)递归技术。反复使用分治策略将这些子问题分成更小的同类型子问题,直至产生出不用进一步细分就可求解的子问题。 3)合并技术. (2)MaxMin算法分析 问题:在含有n个不同元素的集合中同时找出它的最大和最小元素。 分治策略设计思想: 将任一实例I=(n,A(1),…,A(n))分成两个实例如果MAX1和MIN1是I1中的最大和最小元素,MAX2和 MIN2是I2中的最大和最小元素, MAX1和MAX2中的大者就是I 中的最大元素MAX, MIN1和MIN2中的小者是I中的最小元素MIN。如果I只包含一个元素,则不需要作任何分割直接就可得到其解。 核心算法如下: procedure MAXMIN(i,j,fmax,fmin) global n,A[1:n] case { i =j : fmax ←fmin ←A [i ] /*只有一个元素*/ i =j-1:if A[i ] 〈A[j ] then /*两个元素*/ fmax ←A [j ] ;fmin ←A [i ] else fmax ←A[i] ;fmin ←A[j ] else :mid ← /*分成两部分*/ MAXMIN(i,mid ,max1,min1) MAXMIN (mid+1,j ,max2,min2) fmax ←max(max1,max2) fmin ←min(min1,min2) } MAXMIN 的时间复杂性分析 用T(n)表示比较次数,则所导出的递归关系式: ⎣⎦⎡⎤⎪⎩ ⎪⎨⎧++=2)2/()2/(1 0)(n T n T n T 当n 是2的幂时,即对于某个正整数k ,n=2k,有 T (n)=2T (n/2)+2 =2(2T (n/4)+2)+2 =4T(n/4)+4+ =2k —1T(2)+2k —1+……+2 =2k —1+2k-2 =3n/2-2 对于任意 n ,存在整数k ,有2k-1 2、动态规划 (1)动态规划核心思想 动态规划法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,但是经分解得到的子问题往往不是互相独立的。用分治法求解时,有些子问题被重复计算了许多次。 如果能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,就可以避免大量重复计算,从而得到多项式时间算法。 设计动态规划法的步骤: 1、划分阶段(子问题),分析最优子结构性质。 2、找出阶段间的最优决策的递推关系,写出动态规划方程; 3、设计自底向上计算出最优值的步骤. 4、从最终决策的回溯子问题的决策,构造一个最优解。 (2)矩阵连乘算法分析 问题:给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2…,n-1。如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。 两个矩阵相乘所需做的数乘次数为 l*n*m,矩阵乘法满足结合律,故矩阵连乘有可以有许多不同的计算顺序。计算顺序由加括号的方式确定,加括号的方式决定了矩阵连乘的计算量。 核心算法如下: 依次计算各层的子问题集 r=1,初始化 for i ← 1 to n do m[i][i]← 0 从 r=2至 r=n for r← 2 to n do 计算所有大小为r的子问题 MatrixChain(p[0:n], n,m[1:n][1:n],s [1:n][1:n]) { 1) for i ← 1 to n do //初始化 m[i][i] ← 0 2) for r ← 2 to n do // 子问题由小到大 3) for i ← 1 to n — r+1 do //子问题的起点 4){j←i+r-1 //子问题的终点 5) m[i][j]←m[i+1][j]+ p[i—1]*p[i]*p[j] // 初值考虑 6) s[i][j]← i // 记录分割点 7) for k← i+1 to j-1 do //求最好的分割k 8) { t←m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j]; 9) if t 〈 m[i][j] then 10) { m[i][j]← t 11) s[i][j] ← k } }} } 3、贪心法 (1)贪心法核心思想 顾名思义,贪心算法总是作出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择.希望通过局部最优选择,达到全 局的最优 作出贪心决策的依据称为贪心准则(greedy criterion)。 虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。 贪心法一般方法 1)根据题意,选取一种量度标准。 2)按这种量度标准对这n 个输入排序, 3)依次选择输入量加入部分解中。如果当前这个输入量的加入,不满足约束条件,则不把此输入加到这部分解中。 (2)背包问题算法分析 问题:已知有n 种物品和一个可容纳M 重量的背包,每种物品i 的重量为wi 。假定将物品i 的一部分xi 放入背包就会得到pixi 的效益,这里,0≤xi ≤1,pi>0.如果这些物品重量的和大于M ,要求所有选中要装入背包的物品总重量不得超过M,而装入背包物品获得的总效益最大。即 , max 1i i i x p ∑≤≤M x w i n i i =∑≤≤1 满足约束条件的任一集合(x1,…,xn)是一个可行解(即能装下),使目标函数取最大值的可行解是最优解。 核心算法如下: 用利润/重量为量度 即每一次装入的物品应使它占用的每一单位容量获得当前最大的单位效益。这就需使物品的装人次序按pi/wi 比值的非增次序来考虑。 procedure KNAPSACK(real P,W ,M,X ,n) { //P(1:n)和W (1:n )分别是n 个物品的重量,它们已按 P(i )/W (i )≥P (i+1)/W(i+1)排序,x(1:n )是解向量// real cu ;int i ,n ; X ←0 //将解向量初始化为零// cu ←M //cu 是背包剩余容量// for i ←1 to n do {if W[i ]>cu then break X[i] ←1 cu ←cu —W [i ] } if i ≤n then X [i ] ←cu/ W [i ] } (3)装载问题算法分析 问题:有一批集装箱要装上一艘载重量为M的轮船。其中集装箱i的重量为Wi。 最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船 设装载入船的集装箱的子集为S max{∑i | i ∈S,1≤i ≤n} 约束∑w[i]≤M ,1≤i ≤n, i ∈S 核心算法如下: 采用重量最轻者先装的贪心选择策略 Loading( M, n) global W[1.。n],X[1。.n] // W[1.。n] 为非递减序 X ←0 // 解向量清0 cu ←M for i←1 to n do { if cu break X[i]← 1 cu ← cu —W[i] } 4、回溯法 (1)回溯法核心思想 回溯法是一种组织得井井有条的,能避免不必要搜索的穷举式搜索法.这种方法适用于解一些组合数相当大的问题。 回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树. 算法搜索至解空间树的任意一点时,先判断该结点是否满足约束。如果不满足,则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。 回溯法的一般步骤: (1)针对所给问题,定义问题的解空间; (2)确定易于搜索的解空间结构; (3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。 (2)N皇后问题非递归算法分析 问题:n皇后问题可以表示成n—元组(x1,…,xn),其中xi是放在第i行的皇后所在的 列号.于是,解空间由nn个n—元组组成。 显示约束条件为Si={1,2,……。,n},1i n。 隐式约束条件之一为没有两个xi相同(即任意两个皇后不在同一列上)。将其加入到显式条件中,于是解空间的大小由nn个元组减少到n!个元组。 核心算法如下: procedure NQUEENS(n) X(1)←0;k←1 //k是当前行;X(k)是当前列// While k>0 do //对所有的行执行以下语句// 1){ X(k)←X(k)+1 //移到下一列// While X(k)≤n and not PLACE(k) do 2) X(k)←X(k)十l if X(k)≤n //找到一个位置// then if k=n //是一个完整的解吗// then print(X) //是,打印这个数组// 3) else {k←k+1;X(k)←0;} 4) else k←k-1 //回溯// } end NQUEENS 测试X(K)是否合理 procedure PLACE(k) //如果一个皇后能放在第k行和X(k)列,则返 回true;否则返回false。X是一个全程数 组,进入此过程时已置了k个值。// global X(1:k); integer i,k i←1 while i if X (i)=X(k) //在同一列有两个皇后// or ABS(X(i)-X(k))=ABS(i-k) //在同——条斜角线上// then return(false) endif i←i+1 repeat return(true) //满足约束// end PLACE (3)N皇后问题递归算法分析 使用递归算法使,反复的调用判断函数,判断后在决定位置。 核心算法如下: public void setposition(int n) //n表示在第n行,table[n]表示列数 { for(int i = 0; i <= 5; i++) //i表示在第i列上放置皇后 { x[n] = i; if(place(n)==false ) //如果没有皇后在同一列或斜线上(因为是按行依次放置故不可能在同一行上,又因为是每一行是从左到右放置故不可能出现右斜线上有皇后) { if(n == 5) //棋盘满时输出方案 { count++; System。out。println("第" + count + ”种解:”); for(int j=0;j〈=5;j++){ System.out.print(x[j]+1+" ”); }System.out.println(""); //print(); } else //一个棋盘未放满时继续放置 setposition(n + 1); } } } 三、例子说明 经上机操作,各个经典问题的算法实现实现如下: 1、MaxMin问题 比较10个数字的大小,10, 23, 45, 11, 757, 2, 1236, 768, 1,—9 比较得出最大值为1236,最小值为-9。 2、矩阵连乘 给定6个矩阵A(30*35),B(35*15),C(15*5),D(5*10),E(10*20)G(20*25)。 3、背包问题 给定3个背包:三个物品的价值分别为60,120,100,三个物品的质量分别是10,30,20,背包容量为50。 得到装入物品的比例分别为1,2/3,1,总重量为50,最大价值为240. 4、最优装载 船的称重量为20,给定10个物品,重量分别是: 1。0f,5。0f,2.0f,2。0f,4。0f,8。0f,3。0f,1。0f,6。0f,2.0f 5、N皇后问题(非递归) 给定4皇后问题,得到4种解。 6、N皇后问题(递归)给定6皇后问题,得到4种解。 四、心得体会 学习了栾老师的算法课,解决很多问题,老师说程序=算法+数据结构,首先老师教的知识对于逻辑思维能力有很大帮助,它可以培养我们思考分析问题能力,所谓算法简单来说,就是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,,之前学习,学习了算法的时间空间复杂度分析,之后讲的就是分治法,任何一个可用计算机求解的问题所需要的计算时间都与其规模有关。问题的规模越小,越容易直接求解,解题所需要的时间也越少,分治法的设计思想就是将一个难以解决的大问题,分割成为规模小的问题,分别解决。之后有动态规划问题各种问题,算法是一门基础学科应该学好.对于自己在以后的学习会有很大的帮助。 五、算法对应的例子代码 1、求最大值最小值 /*使用分治法求最大值最小值T(n)=3n/2-2*/ public class MaxMin { static int count=0; public static void main(String args[]) { //实例化对象 MaxMin maxmin = new MaxMin(); //创建数组 int[] array = new int[] { 10, 23, 45, 11, 757, 2, 1236, 768,1,-9 }; //取得最小值 int max = maxmin.getMax(array, 0, array.length—1); int min = maxmin.getMin(array,0,array。length-1); //输出 System。out。println("最大值是:”+max); System.out。println(”最小值是:"+min); } /* 求最大值*/ public static int getMax(int[] array,int i,int j) { int Max1 = 0; int Max2 = 0; if(i == j) { return Max1 = Max2 = array[j]; }else if (i == (j — 1)) { Max1 = array[i]; Max2 = array[j]; return Max1 〉 Max2 ? Max1 : Max2; } else { int mid = (i + j) / 2; Max1 = getMax(array, i, mid); Max2 = getMax(array, mid, j); // count++; //System.out。println(count); return Max1 > Max2 ? Max1 : Max2; } } /*求最小值*/ public static int getMin(int[]array,int i,int j){ i nt Min1=0; i nt Min2=0; i f(i==j){ return Min1=Min2=array[j]; }else if(i==(j-1)){ Min1=array[i]; Min2=array[j]; return Min1〉Min2?Min2:Min1; }else{ int mid=(i+j)/2; Min1=getMin(array,i,mid); Min2=getMin(array,mid,j); return Min1〉Min2?Min2:Min1; } } } 2、矩阵连乘问题 /*矩阵连乘问题,i,r,k的三重循环,时间复杂度为O(n立方)*/ public class MatrixChainOrder { int[] p;//矩阵维数 int[][] m;//最少乘次数 int[][]s;//分割点 int length; public MatrixChainOrder(int[] p,int[][] m,int[][] s){this.p = p; this。length = p。length/2; this.m = m; this。s = s; init(); clac(); printM(); } public void init(){ //m初始化 for (int i=0;i m[i][i] = 0; } } public void clac(){ for(int i=1;i〈length;i++){ for(int j=0;j〈length-i;j++){ int r = j+i; //重复计算子问题,长度由1,到length int t = Integer.MAX_VALUE;//定义当前最大值 for(int k = j;k int temp = m[j][k] + m[k+1][r] + p[j*2]*p[k*2+1]*p[r*2+1]; if (t 〉 temp){ t = temp; m[j][r] = temp; } } } } } public void printM(){ for (int i=0;i for(int j=0;j System.out。print(m[i][j]+ ”\t”); } System.out。println(); } } public static void main(String args[]){ int p[] = {30,35,35,15,15,5,5,10,10,20,20,25}; int length = 6; int[][] m = new int[6][6]; int[][] s = new int[6][6]; new MatrixChainOrder(p,m,s); } } 3、背包问题 /* 利用贪心算法,对背包问题的java实现*/ public class Knapsack { private float m;//背包容量 float[] v;//三个物品的价值 float[] w ; //三个物品的质量 float[]x ; //往背包装东西的比例 int n ; //物品个数 double[] p_w_v;//每个物品的单位重量价值 public Knapsack(){ this.m = 50。0f ; //背包容量为50 this。v = new float[]{60。0f,120.0f,100。0f} ; //三个物品的价值分别为60,120,100 this。w = new float[]{10。0f,30。0f,20。0f,} ; //三个物品的质量分别是10,30,20, this.x = new float[3];//往背包装东西的比例 this.n = 3 ;//三个物品 this.p_w_v = new double[n];//每个物品的单位重量价值 } //对物品的单位重量价值进行排序 public void sort(int n ,float[] v ,float[] w)throws Exception{ for (int i = 0 ; i 〈 n ; i++){ p_w_v[i] = v[i] / w[i] ;//单位重量价值 } print (p_w_v); System.out.println ("”); Sort(p_w_v,w,v) ; print (p_w_v); } public void print (double a[]){//打印输出数组 int len = a。length; for (int i = 0; i < len; i++){ System.out。print(a[i] + ” "); } } public void print (String str){//打印输出数组 System.out。print(str + ”\n”); } public void Sort(double[] a , float[] b ,float[] c){//冒泡排序,实现排序功能 int len = a.length;//获得数组长度 double temp;//临时变量,用于交换值 float w_temp ; float v_temp ; for(int i = 0; i 〈 len-1; i++){//通过循环实现主要算法 for(int j = 0; j < len—1-i; j++){ if(a[j+1] > a[j]){ //如果后一下值比前一个值大,则交换两个值的大小, //以下几行代码是实现数值交换的 temp = a[j+1];//从大到小排序 w_temp = w[j+1]; v_temp = v[j+1]; a[j+1] = a[j]; w[j+1] = w[j]; v[j+1] = v[j]; w[j] = w_temp; v[j] = v_temp; } } } } //贪心算法核心思想 public void knapsack()throws Exception{ sort (n,v,w) ; int i ; for (i = 0 ; i 〈n ; i++){ x[i] = 0 ; } float c = m; for (i = 0 ; i < n; i++){ if(w[i] 〉 c){ break ; } x[i] = 1 ; c —= w[i] ; } if(i 〈n){ x[i] = c / w[i] ; } print ("\n物品一可以装入的比例: " + x[0]); print (”物品二可以装入的比例: " + x[1]); print (”物品三可以装入的比例:” + x[2]); print ("可以装入的最大价值为: "+ (x[0]*v[0] + x[1]*v[1] + x[2]*v[2])); print ("可以装入的最大重量为"+ (x[0]*w[0] + x[1]*w[1] + x[2]*w[2])); } public static void main (String[] args)throws Exception{ Knapsack ksp = new Knapsack(); ksp.knapsack(); } } 4、装载问题 /*装载问题,贪心法,时间复杂度上界函数为O(n方)*/ public class Loading { private float m;//船的称重量 private float w[];//物品的质量 int[]x;//物品的选择 int n;//物品个数 public Loading(){ this.m=20。0f;//船的称重量为20 this.n=9;//10个物品 this。w=new float[]{1。0f,5.0f,2。0f,2.0f,4.0f,8.0f,3。0f,1.0f,6.0f,2.0f};//10个物品的重量 this。x=new int[n]; System。out。println("给定的10个可选货物为:"); for(int i=0;i〈w。length;i++){ System。out。print(w[i]+” "); } System.out。println("”); } //对物品按照重量进行排序 public void sort(){ float temp=0f; for(int i=0;i for(int j=0;j if(w[j]>w[j+1]){ temp=w[j]; w[j]=w[j+1]; w[j+1]=temp;} } } System.out.println(”排序后的数据为:"); for(int i=0;i〈w.length;i++){ System。out。print(w[i]+””); } } public void loading(){ int i; System.out.println(); System.out。println("贪心选择为:"); for(i=0;i〈n;i++){ x[i]=0; } for(i=0;i〈n;i++){ if(w[i]>m){ break; } x[i]=1; m=m-w[i]; if(m<0){ break; } System.out。print(w[i]+” ”); } } public static void main(String[]args){ Loading load=new Loading(); load.sort(); load。loading(); } } 5、N皇后问题(非递归) /*回溯法N皇后问题,非递归算法,时间复杂度为O(n!)*/ public class Queen1 { static int count = 0; static int n = 6; static int x[] = new int[n+1]; void backtrack() { int k = 1; while (k 〉 0) { x[k] += 1; // 第k列皇后向下移一行 while((x[k] 〈= n) && !(place(k))) { // 如果当前第k列皇后未出界或者和其他皇后冲突 x[k] += 1; // 第k列皇后向下移一行继续寻找 } if(x[k]〈= n){// 找到一个值并且未出界 if (k == n) { // 已是最后一列说明已找到一个方案 count++; System.out.println("第" + count + "种解:"); for(int i=1;i<=k;i++) {//打印寻找策略 System.out.print(x[i]+” ”); } System。out。println(); } // print();} else { // 不是最后一列故寻找下一列 k++; x[k] = 0; } } else // 找到的值已经出界,回退到上一列 k-—; } } // 判断皇后是否冲突 boolean place(int k) { for(int j = 1; j < k; j++) { if((Math.abs(j —k) == Math。abs(x[j] —x[k]))|| (x[j]== x[k])) return false; } return true; } public static void main(String[] args) { for(int i = 0;i〈n;i++){ x[i] = 0; } Queen1 huanghou = new Queen1(); huanghou。backtrack(); } } 6、N皇后问题(递归) /*回溯法N皇后问题,递归算法*/ public class Queen { private int[]x = new int[6]; private int count = 0; public Queen() { setposition(0); } public void setposition(int n) //n表示在第n行,table[n]表示列数 { for(int i = 0; i 〈= 5; i++) //i表示在第i列上放置皇后 { x[n] = i; if(place(n)==false)//如果没有皇后在同一列或斜线上(因为是按行依次放置故不可能在同一行上,又因为是每一行是从左到右放置故不可能出现右斜线上有皇后) { if(n == 5) //棋盘满时输出方案 { count++; System。out.println(”第" + count + ”种解:"); for(int j=0;j〈=5;j++){ 算法分析与设计实验报告 学生姓名:系别:专业与班号:学号: 实验名称:Strassen’s 矩阵乘法和最近点对算法 实验目的 1、理解“分治法”算法设计思想及其实现步骤 2、掌握分治算法效率递归分析方法 3、掌握主方式求解递归式方法 实验内容及要求 1、利用计算机程序设计语言,实现教材第28.2 章介绍的“Strassen’s 矩阵乘法算法”,自主生成两个8×8 的矩阵,检验算法的正确性并输出算法结果。 2、比较 Strassen’s 矩阵乘法算法和数学定义的矩阵乘法算法效率之间的区别,并用直观的表达方式把两种不同矩阵乘法的效率随矩阵维数的变化趋势。 3、利用计算机程序设计语言,实现教材第33.4 章介绍的“最近点对算法”,在拟定的二维空间点集上检验算法的正确性并输出算法结果。 实验原理 1.Strassen’s矩阵乘法简介 Strassen’s算法是将矩阵分成了如图所示的均等的四块。分后的每一块儿任然还是方阵。 所以可以由大问题分解成若干子问题进行解决。为了能使子问题能够返回到原始问题。 Strassen‘s算法提出了如下的计算公式,可以用矩阵的子矩阵计算出S1-S7,然后又由S1-S7合成原始矩阵。而S1-S7的计算又是方阵的乘法。由此使用分治算法便可以解决问题。 2.最近点对问题(Closest Pair Problems)算法简介 首先这个问题也是采用了分治的思想,将空间内的距离分成三类,分界线左边的点之间的距离,分界线右边的点之间的距离,还有分界线两边距离为D 的区域内的两点间距离。 算法具体代码 1.矩阵相乘问题 // Strassen.cpp : 定义控制台应用程序的入口点。 // //******************************************************************************** #include "stdafx.h" #include "stdlib.h" #define AM Copy(A,0,0,A.v/2) #define BM Copy(A,A.v/2,0,A.v/2) #define CM Copy(A,0,A.v/2,A.v/2) #define DM Copy(A,A.v/2,A.v/2,A.v/2) #define EM Copy(B,0,0,B.v/2) #define FM Copy(B,B.v/2,0,B.v/2) #define GM Copy(B,0,B.v/2,B.v/2) #define HM Copy(B,B.v/2,B.v/2,B.v/2) #define V 2 //******************************************************************************** //矩阵结构 typedef struct matrix { int v; int x[16][16]; }Matrix; //******************************************************************************** //输入输出文件 FILE *fout; FILE *fin; //******************************************************************************** //矩阵打印(文件) void fPrint(Matrix A) { for(int j=0;j 《算法设计与分析》实验报告实验三回溯法 3.迷宫问题 一天Luna在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由n * n的格点组成,每个格点只有2种状态,. 和#,前者表示可以通行后者表示不能通行。同时当Luna处在某个格点时,她只能移动到东南西北(或者说上下左右)四个方向之一的相邻格点上,Luna想要从点A走到点B(不能走出迷宫)。如果起点或者终点有一个不能通行(为#),则看成无法办到。 [输入] 第1行是测试数据的组数k,后面跟着k组输入。 每组测试数据的第1行是一个正整数n (1 <= n <= 100),表示迷宫的规模是n * n 的。 接下来是一个n * n的矩阵,矩阵中的元素为. 或者#。 再接下来一行是4个整数ha, la, hb, lb,描述A处在第ha行, 第la列,B处在第hb 行, 第lb列。注意到ha, la, hb, lb全部是从0开始计数的。 1.八皇后问题 1.1解题思路 八皇后问题的解法,很简单的解法。通过回溯实现枚举。 对于当前行,尝试是否可在当前列放置皇后,然后进入下一行的尝试,同时尝试完毕以后,要将当前行回复(回溯),来进行下一次尝试。 到达最后一行的时候,即递归结束条件,打印结果即可。 1.2程序运行情况 1.3所有的皇后解 见附录。(毕竟92个解...) 1.4程序源码(含注释) 2. 24点问题 2.1 解题思路 这题虽然使用dfs很简单,但是有一点思维在里面。我很惭愧,自己没有想出来怎么如意的独立AC此题。 遇到的最大的问题——如何插入括号?枚举插入、和运算符一同排列都不靠谱。解决方法是:用同等的办法转化。每一次从待组合的是数字中,任取两个数,随机用运算符计算完毕后,再放回去。下一次计算,再次重复这个过程,可以等价为有括号的运算方式了。 遇到第二个问题——如何实现这种“任取两个数”的选择方式。这里就直接体现出了我个人能力的不足。居然没想到。尝试使用STL的set,但是没成功。这里借鉴了网上的AC 思路,我感到自己思维太僵硬。解决方法是——对于当前的运算状态中,用两个循环实现枚举两个数,计算为完毕以后,结果覆盖在数组序号小的那个数的位置,再将第二个数与最后一个数字交换即可进入下一个状态。回溯的时候,只需要回复小序号的数字的位置的值,以及再一次swap即可。(因为第二个数字只是swap却没有改变过内容)。 一个细节问题,就是加法和乘法是没有顺序的,减法和除法是有顺序的,以及除法要考虑0异常。一共是6次枚举即可。 2.2 测试样例 5 5 5 1 ans is YES 1 1 4 2 ans is :NO 2.3 程序运行情况 样例一: 实验一递归1.1实验目的 1)掌握递归算法的概念,理解递归算法的思想 2)掌握递归函数的写法,熟练运用递归函数 3)正确分析递归算法的时空复杂度 1.2 实验内容 1)编写程序递归地实现阶乘函数; 2)编写程序递归地实现Fibonacci数列; 3)编写程序递归实现整数划分问题 1.3 实验步骤 1)写出阶乘函数的定义公式 n!=1 n=0 n n?1! n>0 2)创建一个java程序,递归实现阶乘函数public static int factorial(int n) { if(n==0) return 1; return n*factorial(n-1); } 3)写出Fibonacci数列的定义公式 F n=1 n=0,1 F n?1+F n?2 n>1 4)创建一个java程序,递归实现Fibonacci数列public static int fibonacci(int n) { if(n<=1) return 1; return fibonacci(n-1)+fibonacci(n-2); } 5)分析并写出整数划分的递归公式 q n,m=1 n=1,m=1 q n,n n public static int q(int n,int m) { if((n<1)||(m<1)) return 0; if((n==1)||(m==1)) return 1; if(n 实验一分治与递归(4学时) 一、实验目的与要求 1、熟悉C/C++语言的集成开发环境; 2、通过本实验加深对递归过程的理解 二、实验内容 掌握递归算法的概念和基本思想,分析并掌握“整数划分”问题的递归算法。 三、实验题 任意输入一个整数,输出结果能够用递归方法实现整数的划分。 四、程序代码 五、实验结果 首先按照提示输入数字: 按回车键,得到此数划分的个数: 此时您可以接着计算另一个数的划分个数: 若要退出,请输入一个小于等于零的数: 六、结果分析及程序功能 经过和其它同学的实验数据对比,初步认定此程序基本正确,然而不足之处是只能得到划分的个数,而不能列出每个划分的详细情况。 一、实验目的与要求 1、掌握棋盘覆盖问题的算法; 2、初步掌握分治算法 二、实验题 盘覆盖问题:在一个2k×2k个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。 三、程序代码 四、实验结果 按照提示输入特殊方格的行号和列号(起始行列号为0): 按回车键,得到一个矩阵,数字相同区域为一个L型骨牌覆盖: 五、结果分析及程序功能 得到的16*16棋盘覆盖结果正确,此程序的不足之处:只能设定特殊方格的行列号,而不能设定棋盘的大小。 实验二动态规划算法(4学时) 一、实验目的与要求 1、熟悉最长公共子序列问题的算法; 2、初步掌握动态规划算法; 二、实验题 若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。 三、实验程序 本科实验报告 课程名称:算法设计与分析 实验项目:递归与分治算法 实验地点:计算机系实验楼110 专业班级:物联网1601 学号:2016002105 学生姓名:俞梦真 指导教师:郝晓丽 2018年05月04 日 实验一递归与分治算法 1.1 实验目的与要求 1.进一步熟悉C/C++语言的集成开发环境; 2.通过本实验加深对递归与分治策略的理解和运用。 1.2 实验课时 2学时 1.3 实验原理 分治(Divide-and-Conquer)的思想:一个规模为n的复杂问题的求解,可以划分成若干个规模小于n的子问题,再将子问题的解合并成原问题的解。 需要注意的是,分治法使用递归的思想。划分后的每一个子问题与原问题的性质相同,可用相同的求解方法。最后,当子问题规模足够小时,可以直接求解,然后逆求原问题的解。 1.4 实验题目 1.上机题目:格雷码构造问题 Gray码是一个长度为2n的序列。序列无相同元素,每个元素都是长度为n的串,相邻元素恰好只有一位不同。试设计一个算法对任意n构造相应的Gray码(分治、减治、变治皆可)。 对于给定的正整数n,格雷码为满足如下条件的一个编码序列。 (1)序列由2n个编码组成,每个编码都是长度为n的二进制位串。 (2)序列中无相同的编码。 (3)序列中位置相邻的两个编码恰有一位不同。 2.设计思想: 根据格雷码的性质,找到他的规律,可发现,1位是0 1。两位是00 01 11 10。三位是000 001 011 010 110 111 101 100。n位是前n-1位的2倍个。N-1个位前面加0,N-2为倒转再前面再加1。 3.代码设计:算法分析与设计实验报告一
算法设计与分析---回溯实验报告
算法设计与分析实验
算法与设计实验报告
算法设计与分析实验报告
算法分析与设计实验报告-合并排序、快速排序