实验一 递归与分治策略
一、实验目的
1.加深学生对分治法算法设计方法的基本思想、基本步骤、基本方法的理解与掌握;
2.提高学生利用课堂所学知识解决实际问题的能力;
3.提高学生综合应用所学知识解决实际问题的能力。
二、实验内容
1、
①设a[0:n-1]是已排好序的数组。请写二分搜索算法,使得当搜索元素x不在数组中时,返回小于x的最大元素位置i和大于x的最小元素位置j。当搜索元素在数组中时,i和j相同,均为x在数组中的位置。
②写出三分搜索法的程序。
三、实验要求
(1)用分治法求解上面两个问题;
(2)再选择自己熟悉的其它方法求解本问题;
(3)上机实现所设计的所有算法;
四、实验过程设计(算法设计过程)
1、已知a[0:n-1]是一个已排好序的数组,可以采用折半查找(二分查找)算法。如果搜索元素在数组中,则直接返回下表即可;否则比较搜索元素x与通过二分查找所得最终元素的大小,注意边界条件,从而计算出小于x的最大元素的位置i和大于x的最小元素位置j。
2、将n个元素分成大致相同的三部分,取在数组a的左三分之一部分中继续搜索x。如果x>a[2(n-1)/3],则只需在数组a的右三分之一部分中继续搜索x。上述两种情况不成立时,则在数组中间的三分之一部分中继续搜索x。
五、实验结果分析
二分搜索法:
三分搜索法:
时间复杂性:
二分搜索每次把搜索区域砍掉一半,很明显时间复杂度为O(log n)。(n代表集合中元素的个数)
三分搜索法:O(3log3n)
空间复杂度:O(1)。
六、实验体会
本次试验解决了二分查找和三分查找的问题,加深了对分治法的理解,收获很大,同时我也理解到学习算法是一个渐进的过程,算法可能一开始不是很好理解,但是只要多看几遍,只看是不够的还要动手分析一下,这样才能学好算法。
七、附录:(源代码)
二分搜索法:
#include<iostream.h>
#include<stdio.h>
int binarySearch(int a[],int x,int n)
{
int left=0;int right=n-1;int i,j;
while(left<=right)
{
int middle=(left+right)/2;
if(x==a[middle]){i=j=middle;return 1;}
if(x>a[middle])left=middle+1;
else right=middle-1;
}
i=right;j=left;
return 0;
}
int main()
{ int a[10]={0,1,2,3,4,5,6,7,8,9};
int n=10;
int x=9;
if(binarySearch(a,x,n))
cout<<"找到"<<endl;
else
cout<<"找不到"<<endl;
return 0;
}
实验二 动态规划——求解最优问题
一、实验目的
1.加深学生对动态规划算法设计方法的基本思想、基本步骤、基本方法的理解与掌握;
2.提高学生利用课堂所学知识解决实际问题的能力;
3.提高学生综合应用所学知识解决实际问题的能力。
二、实验内容
1、用两台处理机A和B处理n个作业。设第i个作业交给机器A处理时所需要的时间是a[i],若由机器B来处理,则所需要的时间是b[i]。由于各作业的特点和机器的性能关系,很可能对于某些i,有a[i]>=b[i],而对于某些就j,j!=i,有a[i]<b[j]。既不能将一个作业分开由两台机器处理,也没有一台机器能同时处理2个作业。设计一个动态规划算法,使得这两台机器处理完这n个作业的时间最短(从任何一台机器开工到最后一台机器停工的总的时间)。研究一个实例:(a[1],a[2],a[3],a[4],a[5],a[6])=(2, 5, 7, 10, 5, 2); (b[1],b[2],b[3],b[4],b[5],b[6])= (3, 8, 4, 11, 3, 4)。
2、长江游艇俱乐部在长江上设置了n个游艇出租站1,2……n。游客可在游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金r(i,j)1<=i<j<=n。设计一个算法,计算出游艇1到游艇n所需最少租金。
三、实验要求
(1)用动态规划思想求解最优问题;
(2)再选择自己熟悉的程序设计语言实现所有算法;
(3)分析所设计的算法的时间/空间复杂性。
四、实验过程设计(算法设计过程)
1、对于给定的2台处理机A和B处理n个作业,找出一个最优调度方案,使2台机器处理完这n个作业的时间最短。
2、对于给定的游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i<j<=n,计算出游艇1到游艇n所需最少租金。
五、实验结果分析
独立任务最优调度问题:
租用游艇问题:
时间复杂性:独立任务最优调度问题:O(n*Sum)
六、实验体会
对于算法来说,没有最好,只有更好,算法的结果不一定是最佳答案,但至少是最接近最佳答案的。在权衡算法时间复杂度和空间复杂度的情况下,找到一个在时间和空间都能接受的算法才是上上之策。
七、附录:(源代码)
独立任务最优调度问题:
using System;
namespace zydd
{
class Program
{
static void DlrwZydd(int[] a, int[] b, int n, int[] least, string[] result)
{
for (int i = 0; i < n; i++)
{
least[i] = 99;
}
int aSum = 0, bSum = 0;
for (int i = 0; i < n; i++)
{
aSum += a[i];
bSum += b[i];
}
int Sum = 1 + Math.Min(aSum, bSum);
int[,] timeA = new int[n, Sum];
int[,] timeB = new int[n, Sum];
int[,] timeMax = new int[n, Sum];
char[,] who = new char[n, Sum];
char[] tempRlt = new char[n];
for (int i = 0; i <= a[0]; i++)
{
timeA[0, i] = i;
if (i < a[0])
{
timeB[0, i] = b[0];
who[0, i] = 'b';
}
else
{
timeB[0, i] = 0;
who[0, i] = 'a';
}
timeMax[0, i] = Math.Max(timeA[0, i], timeB[0, i]);
}
if (a[0] <= b[0])
{
least[0] = a[0];
tempRlt[0] = 'a';
}
else
{
least[0] = b[0];
tempRlt[0] = 'b';
}
result[0] = new String(tempRlt);
for (int k = 1; k < n; k++)
{
int tempSum = 0;
for (int temp = 0; temp <= k; temp++)
{
tempSum += a[temp];
}
for (int i = 0; i <= tempSum; i++)
{ timeA[k, i] = i;
if (i < a[k])
{
timeB[k, i] = timeB[k - 1, i] + b[k];
who[k, i] = 'b';
}
else
{
if ((timeB[k - 1, i] + b[k]) <= timeB[k - 1, i - a[k]])
{
timeB[k, i] = timeB[k - 1, i] + b[k];
who[k, i] = 'b';
}
else
{
timeB[k, i] = timeB[k - 1, i - a[k]];
who[k, i] = 'a';
}
}
timeMax[k, i] = Math.Max(timeA[k, i], timeB[k, i]);
}
for (int i = tempSum + 1; i < aSum; i++)
{
timeA[k, i] = tempSum;
timeB[k, i] = 0;
}
int flag = 0;
for (int i = 0; i <= tempSum; i++)
{
if (timeMax[k, i] > 0 && timeMax[k, i] < least[k])
{
least[k] = timeMax[k, i];
flag = i;
}
}
tempRlt[k] = who[k, flag];
for (int i = k; i > 0 && flag > 0; i--)
{
if (tempRlt[i] == 'a')
{
flag -= a[i];
tempRlt[i - 1] = who[i - 1, flag];
}
if (tempRlt[i] == 'b')
{
tempRlt[i - 1] = who[i - 1, flag];
}
}
result[k] = new String(tempRlt);
}
}
static void Main(string[] args)
{
const int N = 6;
int[] a = new int[N] { 2, 5, 7, 10, 5, 2 };
int[] b = new int[N] { 3, 8, 4, 11, 3, 4 };
int[] least = new int[N];
string[] result = new string[N];
DlrwZydd(a, b, N, least, result);
Console.WriteLine();
for (int i = 0; i < N; i++)
{
Console.WriteLine(" 按要求完成前{0}项任务的机器顺序为:" + result[i] + " 时间为:{1}" ,i+1,least[i]);
}
}
}
}
实验三 贪心算法
一、实验目的
1.进一步理解算法设计的基本步骤及各步的主要内容、基本要求
2.加深对贪婪法算法设计方法的理解与应用
3.掌握将算法转化为计算机上机程序的方法
4.培养学生应用所学知识解决实际问题的能力。
二、实验内容
1、设有n个顾客同时等待一项服务。顾客i需要的服务时间为ti,1<=i<=n。应如何安排n个顾客的服务次序才能使总的等待时间达到最小?总的等待时间是每个顾客等待服务时间的综合。
2、一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法,之处应在哪些加油站停靠加油,使沿途加油次数最少。并证明算法能产生一个最优解。
三、实验要求
(1)设计用贪婪法求解“最优服务次序问题”及“汽车加油问题”的算法;
(2)上机实现所设计的算法;
(3)分析所设计的算法的时间/空间复杂性。
四、实验过程设计(算法设计过程)
1、首先将每个顾客所需要的服务时间从小到大排序。然后申请2个数组:st[]是服务数组,st[j]为第j个队列上的某一个顾客的等待时间;su[]是求和数组,su[j]的值为第j个队列上所有顾客的等待时间;
2、设加油次数为k,每个加油站间距离为a[i];i=0,1,2,3……n
1.始点到终点的距离小于N,则加油次数k=0;
2.始点到终点的距离大于N,
① 加油站间的距离相等,即a[i]=a[j]=L=N,则加油次数最少k=n;
② 加油站间的距离相等,即a[i]=a[j]=L>N,则不可能到达终点;
③ 加油站间的距离相等,即a[i]=a[j]=L<N,则加油次数k=n/N(n%N==0)或k=[n/N]+1(n%N!=0);
④ 加油站间的距离不相等,即a[i]!=a[j],则加油次数k通过下面的算法求解。
五、实验结果分析
最优服务次序问题:
时间复杂度为O(nlogn)
汽车加油问题:
时间复杂度为O(n)。
六、实验体会
七、附录:(源代码)
汽车加油问题:
#include<iostream.h>
#include<stdio.h>
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.Write("请输入汽车加满油后可行驶路程: ");
int n = Convert.ToInt32(Console.ReadLine());
Console.Write("请输入途经加油站总数: ");
int k = Convert.ToInt32(Console.ReadLine());
int[] distance = new int[k + 1];//加油站间距
int[] note = new int[k];//记录加油站点
Console.WriteLine("请输入加油站间距!");
for (int i = 0; i <= k; i++)
{//从始点起,加油站间距
Console.Write("站点间距{0}: ", i + 1);
distance[i] = Convert.ToInt32(Console.ReadLine());
}
int count;//记录加油次数
Problem p = new Problem();
count = p.Greedy(distance, note, n);
if (count >= 0)
{
if (count == 0)
Console.WriteLine("汽车不用加油就可到达终点!");
else
{
Console.WriteLine("汽车在旅途中需加{0}次油!", count);
Console.WriteLine("分别在以下加油站加了油:");
for (int i = 0; i < note.Length; i++)
{
if (note[i] != 0)
{//输出需加油站点
Console.WriteLine("第" + note[i] + "个加油站!");
}
}
}
}
else
Console.WriteLine("汽车无法到达终点!");
Console.ReadKey();
}
}
class Problem
{
public int Greedy(int[] d, int[] note, int n)
{
int i, j, s, add = 0, p = 0, k = d.Length;
for (i = 0; i < k; i++)
{
if (d[i] > n)
{//不能到达目的地
return -1;
}
}
for (j = 0, s = 0; j < k; j++)
{
s += d[j];
if (s > n)
{//需要加油
add++;
note[p++] = j;
s = d[j];
}
}
return add;
}
}
}
实验四 回溯法
一、实验目的
1.掌握能用回溯法求解的问题应满足的条件;
2.加深对回溯法算法设计方法的理解与应用;
3.锻炼学生对程序跟踪调试能力;
4.通过本次实验的练习培养学生应用所学知识解决实际问题的能力。
二、实验内容
1、设某一机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得。设w[i][j]是从供应商j处购得的部件i的重量,c[i][j]是相应的价格。试设计一个算法,给出总价格不超过c的最小重量机器设计。
2、设有n 件工作分配给n 个人。将工作i 分配给第j 个人所需的费用为c[i][j]。试设计一个算法,为每一个人都分配1 件不同的工作,并使总费用达到最小。
三、实验要求
(1)用回溯法算法设计方法求解最小重量机器设计问题和工作分配问题;
(2)上机实现所设计的算法;
(3)分析所设计的算法的时间/空间复杂性。
四、实验过程设计(算法设计过程)
1、a.部件有n个,供应商有m个,分别用w[i][j]和c[i][j]存储从供应商j 处购得的部件i的重量和相应价格,d为总价格的上限。
b.用递归函数backtrack(i)来实现回溯法搜索排列树(形式参数i表示递归深度)。
① 若cp>d,则为不可行解,剪去相应子树,返回到i-1层继续执行。
② 若cw>=sum,则不是最优解,剪去相应子树,返回到i-1层继续执行。
③ 若i>n,则算法搜索到一个叶结点,用sum对最优解进行记录,返回到i-1层继续执行;
④ 用for循环对部件i从m个不同的供应商购得的情况进行选择(1≤j≤m)。
c.主函数调用一次Knapsack(1)即可完成整个回溯搜索过程,最终得到的sum即为所求最小总重量。
2、a. 用c[i][j]存储将工作i分配给第j个人所需的费用,用v[j] 标记第j个人是否已分
配工作;
b. 用递归函数backtrack (i, total)来实现回溯法搜索排列树(形式参数i表示递归深
度,n用来控制递归深度,形式参数total表示当前总费用,s表示当前最优总费用):
① 若total>=s,则不是最优解,剪去相应子树,返回到i-1层继续执行;
② 若i >n,则算法搜索到一个叶结点,用s对最优解进行记录,返回到i-1层
继续执行;
③ 采用for循环针对n个人对工作i进行分配(1≤j≤n):
1> 若v[j]==1 ,则第j个人已分配了工作,找第j+1个人进行分配;
2> 若v[j]==0,则将工作i分配给第j个人(即v[j]=1 ),对工作i+1调用递归函数backtrack(i+1,total+c[i][j])继续进行分配;
3> 函数backtrack(i+1,total+c[i][j])调用结束后则返回v[j]=0,将工作i对
第j+1个人进行分配;
4> 当j>n时,for循环结束;
④ 当i=1时,若已测试完c[i][j]的所有可选值,外层调用就全部结束;
c. 主函数调用一次backtrack(1,0)即可完成整个回溯搜索过程,最终得到的s即为
所求最小总费用。
五、实验结果分析
最小重量机器设计问题:
程序中最大的循环出现在递归函数backtrack(i)中,而此函数遍历排列树的时间复杂度为O(n!),故该算法的时间复杂度为O(n!)。
工作分配问题:
递归函数backtrack(i,total)遍历排列树的时间复杂度为O(n!),主函数调用递归函
数backtrack(1,0),故该算法的时间复杂度为O(n!)。
六、实验体会
七、附录:(源代码)
最小重量机器设计问题:
#include<iostream>
#define N 1000
using namespace std;
int n,m,d,cp=0,cw=0,sum=0;
int c[N][N],w[N][N];
void backtrack(int i){
if(i>n){
if(cw<sum)
sum = cw;
return ;
}
for(int j=1;j<=m;j++){
cw+=w[i][j];
cp+=c[i][j];
if(cw<sum && cp<=d)
backtrack(i+1);
cw-=w[i][j];
cp-=c[i][j];
}
}
int main(){
cin>>n>>m>>d;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
cin>>c[i][j];
sum+=c[i][1];
}
for(int k=1;k<=n;k++)
for(int j=1;j<=m;j++)
cin>>w[k][j];
backtrack(1);
cout<<sum<<endl;
system("pause");
return 0;
}
攀枝花学院实验报告实验名称算法设计与分析课程实验实验内容比较排序算法的效率实验日期20xx0326院系数学与计算机姓名吴永昊学号2…
算法设计与分析课程报告课题名称算法设计与分析课题负责人名学号同组成员名单角色指导教师评阅成绩评阅意见提交报告时间20xx年6月12…
计算机算法与设计分析实验报告班级姓名学号目录实验一分治与递归11基本递归算法12棋盘覆盖问题23二分搜索34实验小结5实验二动态规…
算法设计与分析实验报告一实验名称统计数字问题评分实验日期年月日指导教师刘长松姓名刘飞初专业班级计算机0901学号10一实验要求1掌…
算法分析与设计实验报告实验报告题目实验一递归与分治策略一实验目的1加深学生对分治法算法设计方法的基本思想基本步骤基本方法的理解与掌…
算法设计与分析实验报告班级姓名学号20xx年11月18日目录实验一二分查找程序实现01页实验二棋盘覆盖问题04页实验三01背包问题…
算法分析与设计实验报告实验报告题目实验一递归与分治策略一实验目的1加深学生对分治法算法设计方法的基本思想基本步骤基本方法的理解与掌…
算法设计与分析实验报告实验一递归与分治策略应用基础学号姓名班级日期20xx20xx学年第1学期第九周一实验目的1理解递归的概念和分…
算法设计与分析实验报告一实验名称统计数字问题评分实验日期年月日指导教师刘长松姓名刘飞初专业班级计算机0901学号10一实验要求1掌…
武汉理工大学学生实验报告书实验课程名称算法设计与分析开课学院计算机科学与技术学院指导老师姓名何九周学生姓名王鹏学生专业班级软件10…