算法分析与设计实验报告学院:信息科学与工程学院专业班级:指导老师:学号:姓名:目录实验一:递归与分治 (3)1.实验目的 (3)2.实验预习内容 (3)3.实验内容和步骤 (3)4.实验总结及思考 (5)实验二:回溯算法 (6)1.实验目的: (6)2.实验预习内容: (6)3. 实验内容和步骤 (6)4. 实验总结及思考 (9)实验三:贪心算法和随机算法 (10)1. 实验目的 (10)2.实验预习内容 (10)3.实验内容和步骤 (10)4. 实验总结及思考 (13)实验一:递归与分治1.实验目的理解递归算法的思想和递归程序的执行过程,并能熟练编写快速排序算法程序。
掌握分治算法的思想,对给定的问题能设计出分治算法予以解决。
2.实验预习内容递归:递归算法是把问题转化为规模缩小了的同类问题的子问题。
然后递归调用函数(或过程)来表示问题的解。
一个过程(或函数)直接或间接调用自己本身,这种过程(或函数)叫递归过程(或函数).分治:分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。
求出子问题的解,就可得到原问题的解。
3.实验内容和步骤快速排序的基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
源代码:#include<iostream>using namespace std;int num;void swap(int &a,int &b){int temp=a;a=b;b=temp;}void printarray(int *arr){for (int i=1;i<=num;++i)cout<<arr[i]<<" ";cout<<endl;}int partition(int *arr,int p,int r){int x=arr[r];int i=p-1;int j;for(j=p;j<=r-1;j++){if(arr[j]<=x){i=i+1;swap(arr[i],arr[j]);}}swap(arr[i+1],arr[r]);return i+1;}void quicksort(int *arr,int p,int r) {if(p<r){int q=partition(arr,p,r);quicksort(arr,p,q-1);quicksort(arr,q+1,r);}}int main(){int arr[100];cout<<"请输入元组个数:\n";cin>>num;cout<<"请输入元素大小:\n";for (int i=1;i<=num;++i)cin>>arr[i];quicksort(arr,1,num);cout<<"快速排序结果:";printarray(arr);return 0;}程序运行结果:4.实验总结及思考快速排序算法通过对quikesort函数的调用而实现了排序为有序队列,使得问题更加简单方便。
快速排序算法的时空复杂度:快速排序每次将待排序数组分为两个部分,在理想状况下,每一次都将待排序数组划分成等长两个部分,则需要logn次划分。
而在最坏情况下,即数组已经有序或大致有序的情况下,每次划分只能减少一个元素,快速排序将不幸退化为冒泡排序,所以快速排序时间复杂度下界为O(nlogn),最坏情况为O(n^2)。
在实际应用中,快速排序的平均时间复杂度为O(nlogn)。
快速排序在对序列的操作过程中只需花费常数级的空间。
空间复杂度S(1)。
但需要注意递归栈上需要花费最少logn最多n的空间。
实验二:回溯算法1.实验目的:熟练掌握回溯算法2.实验预习内容:回溯算法的几种形式a)用回溯算法搜索子集树的一般模式void search(int m){if(m>n) //递归结束条件output(); //相应的处理(输出结果)else{a[m]=0; //设置状态:0表示不要该物品search(m+1); //递归搜索:继续确定下一个物品a[m]=1; //设置状态:1表示要该物品search(m+1); //递归搜索:继续确定下一个物品}}b)用回溯算法搜索子集树的一般模式void search(int m){if(m>n) //递归结束条件output(); //相应的处理(输出结果)elsefor(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](换回来)}}3.实验内容和步骤8皇后问题:在一个8×8的棋盘里放置8个皇后,要求这8个皇后两两之间互相都不“冲突”。
流程图:源代码//八皇后问题#include <iostream>using namespace std;const int N=8;int x[9];int num = 0; //统计解的个数//输出一种布局void print(int *p,int n){int i,j;cout << num <<":\n";for(i=1; i<=n; i++){for(j=1; j<p[i]; j++)cout <<" - ";cout <<" Q ";for(j=p[i]+1; j<=n; j++)cout <<" - ";cout <<endl;}}//求解n皇后布局void nQueens(int n){int k=1;int j=1, flag=1;x[1]=0;while( k>0 ){x[k]+=1; //转到下一行while( x[k]<=n ){//判断第k个皇后可否放在第x[k]列j=flag=1;while( j<k && flag ){if( x[j]==x[k] || (abs(x[j]-x[k])==abs(j-k)) )flag=0;j++;}if( flag==1 ) //可放break;//如果无解,最后一个皇后就会安排到格子外面去x[k]+=1;}if( x[k]<=n ){//第k个皇后仍被放置在格子内,有解if( k==n ){num++;print(x,N); //输出这种布局}else{k++;x[k]=0; //转到下一行}}else //第k个皇后已经被放置到格子外了,没解,回溯k--; //回溯}}int main(){nQueens(N);cout <<"共有" <<num <<"种布局方法。
\n";return 0;}程序运行结果:4.实验总结及思考通过对八皇后问题的编程学习,让我对搜索策略更深层次的理解,尤其能比较熟练掌握回溯策略——首先将规则给出一个固定的排序,在搜索时,对当前状态(搜索开始时,当前状态是初始状态)依次检测每一条规则,在当前状态未使用过的规则中找到第一条可应用规则,应用于当前状态,得到的新状态重新设置为当前状态,并重复以上搜索。
如果当前状态无规则可用,或者所有规则已经被试探过仍未找到问题的解,则将当前状态的前一个状态(即直接生成该状态的状态)设置为当前状态。
重复以上搜索,直到找到问题的解,或者试探了所有可能后仍找不到问题的解为止。
该问题也可扩展到N皇后问题求解,只需修改程序const int N中的N值即可。
实验三:贪心算法和随机算法1.实验目的熟悉和掌握贪心算法和随机算法,明白其原理与步骤及使用方法2.实验预习内容贪心算法:贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解3.实验内容和步骤背包问题有一个背包,背包容量是M=150。
有7个物品,物品可以分割成任意大小。
源代码:#include<iostream>using namespace std;/*---------贪婪法解决背包问题-------总是对当前的问题做最好的选择,从局部最优到全局最优。
先按物品效益、重量比值升序排序。
然后每次选择比重大的物品装载,知道装满背包为止!*/struct goodinfo{float p; //物品效益float w; //物品重量float X; //物品该放的数量int flag;//物品编号};//按物品效益,重量比值做升序排列//插入排序void InsertSort(goodinfo goods[],int n){int i,j;for(j = 2;j<=n;j++){goods[0] = goods[j];i = j-1;while(goods[0].p>goods[i].p){goods[i+1] = goods[i];i--;}goods[i+1] = goods[0];}}void GreedyMethod(goodinfo goods[],float M,int n) {int i,j;for(i = 1;i<=n;i++){goods[i].X = 0;}for(i = 1;i<n;i++){if(goods[i].w>M)break;goods[i].X = 1;M = M - goods[i].w;}if(i<=n)goods[i].X = M/goods[i].w;//按物品编号做降序排列for(j = 2; j<=n;j++){goods[0] = goods[j];i = j - 1;while(goods[0].flag<goods[i].flag){goods[i+1] = goods[i];i--;}goods[i+1] = goods[0];}cout<<"最优解为:"<<endl;for(i = 1;i<=n;i++){cout<<"第"<<i<<"件物品要放: ";cout<<goods[i].X<<endl;}}int main(){int i,n;float M;goodinfo *goods;cout<<"请输入物品的数量和背包的容量:"<<endl;cin>>n>>M;goods = new struct goodinfo[n+1];for(i = 1;i<=n;i++){goods[i].flag = i;cout<<"请输入物品"<<i<<"的重量和价值:"<<endl;cin>>goods[i].w>>goods[i].p;goods[i].p = goods[i].p/goods[i].w; //物品的效益,重量比}InsertSort(goods,n);GreedyMethod(goods,M,n);return 0;}程序运行结果4.实验总结及思考这个算法的运行时间估计如下:1、计算N个物体的价值重量比,并且为解向量付出之,需要O(n)时间;2、对N个物体的价值重量比按递减的顺序排序,需要O(nlogn)时间;3、对每个物体判断可装入背包的分量,需要O(n)时间。