算法设计与分析大作业报告.docx

上传人:b****6 文档编号:6172457 上传时间:2023-01-04 格式:DOCX 页数:16 大小:254.31KB
下载 相关 举报
算法设计与分析大作业报告.docx_第1页
第1页 / 共16页
算法设计与分析大作业报告.docx_第2页
第2页 / 共16页
算法设计与分析大作业报告.docx_第3页
第3页 / 共16页
算法设计与分析大作业报告.docx_第4页
第4页 / 共16页
算法设计与分析大作业报告.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

算法设计与分析大作业报告.docx

《算法设计与分析大作业报告.docx》由会员分享,可在线阅读,更多相关《算法设计与分析大作业报告.docx(16页珍藏版)》请在冰豆网上搜索。

算法设计与分析大作业报告.docx

算法设计与分析大作业报告

 

《算法设计与分析大作业报告》

班级:

学号:

姓名:

 

分治法大作业报告

问题陈述:

编程实现归并排序算法和快速排序算法,输出排序结果。

输入10组相同的数据,验证排序结果和完成排序的比较次数。

分治法基本思想:

分治法的基本思想是将问题分解成若干个子问题,然后求解子问题。

子问题较原问题要容易些,先得出子问题的解,由此得出原问题的解,这就是所谓“分而治之”的思想。

算法描述:

当要求解一个输入规模为n,且n的取值相当大的问题时,如果问题可以分成k个不同子集合,得到k个不同的可独立求解的子问题,其中1

那末,对于这类问题分治法是十分有效的。

本实验就是通过归并排序和快速排序来体现分治的思想。

1.归并排序的思想:

将A

(1),……,A(N)分成两个集合,对每个集合单独分类,然后将已分类的两个序列归并成一个含N个元素分好类的元素

2.快速排序的思想:

选取A的某个元素做为划分元素,然后将其他元素重新排列,使在划分元素以前出现的元素都小于或等于它,在划分元素之后出现的划分元素都大于等于它。

程序代码:

#include

#include

#include

voidMergeSort(int*data,intx,inty,int*temp)

{intp,q,m,i=x;

if(y-x>1)

{m=x+(y-x)/2;

p=x;

q=m;

MergeSort(data,x,m,temp);

MergeSort(data,m,y,temp);

while(p

{

if(q>=y||(p

{temp[i++]=data[p++];}

else

{temp[i++]=data[q++];}

}

for(i=x;i

data[i]=temp[i];}

}

voidHoareSort(int*data,intx,inty)

{

intp=x,q=y-1,temp;

while(p

while(q>p&&data[q]>=data[p])

q--;

if(q>p)

{

temp=data[p],data[p]=data[q],data[q]=temp;

p++;

}

while(q>p&&data[p]<=data[q])

p++;

if(p

{

temp=data[p],data[p]=data[q],data[q]=temp;

q--;

}

if(p==q){

HoareSort(data,x,p);

HoareSort(data,p+1,y);

}}}

intmain()

{

intdata[10],i;

inttemp[10];

srand(time(NULL));

for(i=0;i<10;i++)

{data[i]=rand()%100;}

printf("未排序排序的数据为:

\n");

for(i=0;i<10;i++)

{printf("%d",data[i]);}

printf("\n");

printf("归并排序的顺序为:

\n");

MergeSort(data,0,10,temp);

for(i=0;i<10;i++)

{printf("%d",data[i]);}

printf("\n");

printf("快速排序的顺序为:

\n");

HoareSort(data,0,10);

for(i=0;i<10;i++)

{printf("%d",data[i]);}

printf("\n");

return0;

}

运行结果:

结论分析:

归并排序和快速排序都是递归排序,但是归并排序是稳定的排序方法,快速排序是不稳定的排序方法。

(1)此问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;

(2)利用该问题分解出的子问题的解可以合并为该问题的解;(3)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。

 

动态规划大作业报告

问题陈述:

定义0-1背包问题为:

限制条件为:

,且

分别表示第i个物品的价值和重量,c为背包容量。

动态规划基本思想:

动态规划算法通常用于求解具有某种最优性质的问题。

在这类问题中,可能会有许多可行解。

每一个解都对应于一个值,我们希望找到具有最优值的解。

动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。

与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。

若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。

如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。

我们可以用一个表来记录所有已解的子问题的答案。

不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。

这就是动态规划法的基本思路。

具体的动态规划算法多种多样,但它们具有相同的填表格式。

算法描述:

刻画0-1背包问题的最优解的结构。

可以将背包问题的求解过程看作是进行一系列的决策过程,即决定哪些物品应该放入背包,哪些物品不放入背包。

如果一个问题的最优解包含了物品n,即xn=1,那么其余x1,x2,...,x(n-1)一定构成子问题1,2,...,n-1在容量W-wn时的最优解。

如果这个最优解不包含物品n,即xn=0,那么其余x1,x2,...,x(n-1)一定构成子问题1,2,...,n-1在容量W时的最优解。

递归定义最优解的值,根据上述分析的最优解的结构递归地定义问题最优解。

设c[i,w]表示背包容量为w时,i个物品导致的最优解的总价值,得到下式。

显然要求c[n,w]。

程序代码:

#include

usingnamespacestd;

voidPath(intn,intW,intc[][100],int*v,int*wei)

{

memset(*c,0,(W+1)*sizeof(int));

for(inti=1;i<=n;i++)

{

c[i][0]=0;

for(intw=1;w<=W;w++)

{

if(wei[i-1]>w)

{

c[i][w]=c[i-1][w];

}

else

{

inttemp=c[i-1][w-wei[i-1]]+v[i-1];

if(c[i-1][w]>temp)

{

c[i][w]=c[i-1][w];

}

else

c[i][w]=temp;

}}}}

voidfind(intc[][100],int*x,int*wei,intn,intW)

{

intw=W;

for(inti=n;i>=2;i--)

{

if(c[i][w]==c[i-1][w])

{

x[i-1]=0;

}

else

{

x[i-1]=1;

w=w-wei[i-1];

}

}

if(c[1][w]==0)

x[0]=0;

else

x[0]=1;

}

intmain()

{

intn=5;

intW=100;

intw[]={10,48,35,23,25,30};

intv[]={40,10,20,30,50};

intc[6][100]={0};

Path(n,W,c,v,w);

cout<<"最优的总价值为:

";

cout<

intx[5];

find(c,x,w,n,W);

cout<<"用0表示不装入,1表示装入,情况如下:

"<

for(inti=1;i

{cout<<"第"<

";

cout<

return0;

}

运行结果:

结论分析:

上述代码的时间复杂度为O(nw)。

能表示出装入或者不装入但计算出装入后的总价值有点问题,程序还不够完善有待改进。

动态规划问题的的实质就是寻求一个最优解的过程,实质就是为问题寻求一个最优算法,这个最优算法解出来的值是运用所有算法中最接近实际值的解。

一般对一个问题,不会运用多种算法,而只会选取其中的一种来求解(但实际问题中常常需要不同算法的结合,不过一般是处理不同方面的算法)不同的算法对待不同的问题总是有利有弊。

 

贪心法大作业报告

问题陈述:

给定n种物品和一个背包.物品i的重量是Wi,其价值为Vi,背包的容量为C。

在选择物品i装入背包时,可以选择物品i的一部分,1<=i<=n。

问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大。

贪心法基本思想:

贪心算法的基本思想是找出整体当中每个小的局部的最优解,并且将所有的这些局部最优解合起来形成整体上的一个最优解。

因此能够使用贪心算法的问题必须满足下面的两个性质:

1.整体的最优解可以通过局部的最优解来求出;

2.一个整体能够被分为多个局部,并且这些局部都能够求出最优解。

使用贪心算法当中的两个典型问题是活动安排问题和背包问题。

算法描述:

对于背包问题,若它的一个最优解包含物品j,则从该最优解中拿出所含的物品j的那部分重量w,剩余的将是n-1个原重物品1,2,…,j-1,j+1,…,n及重为Wj-W的物品j中可装入容量为c-w的背包且具有最大价值的物品。

程序代码:

#include

structgoodinfo

{

floatp;

floatw;

floatX;

intflag;

};

voidInsertionsort(goodinfogoods[],intn)

{

intj,i;

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];

}

}

voidbag(goodinfogoods[],floatM,intn)

{

floatcu;

inti,j;

for(i=1;i<=n;i++)

goods[i].X=0;

cu=M;

for(i=1;i

{

if(goods[i].w>cu)

break;

goods[i].X=1;

cu=cu-goods[i].w;

}

if(i<=n)

goods[i].X=cu/goods[i].w;

for(j=2;j<=n;j++)

{

goods[0]=goods[j];

i=j-1;

while(goods[0].flag

{

goods[i+1]=goods[i];

i--;

}

goods[i+1]=goods[0];

}

cout<<"最优解为:

"<

for(i=1;i<=n;i++)

{

cout<<"第"<

";

cout<

}}

voidmain()

{

cout<<"运用贪心法解背包问题"<

intj;

intn;

floatM;

goodinfo*goods;

while(j)

{

cout<<"请输入物品的总数量:

";

cin>>n;

goods=newstructgoodinfo[n+1];

cout<<"请输入背包的最大容量:

";

cin>>M;

cout<

inti;

for(i=1;i<=n;i++)

{goods[i].flag=i;

cout<<"请输入第"<

";

cin>>goods[i].w;

cout<<"请输入第"<

";

cin>>goods[i].p;

goods[i].p=goods[i].p/goods[i].w;

cout<

}

Insertionsort(goods,n);

bag(goods,M,n);

cout<<"请问您还要继续运行此程序吗?

请用Y或者N回答。

"<

cin>>j;

if(j=='N')

break;

}}

运行结果:

结论分析:

程序较完整,算法复杂度为O(N*N)。

但有一点点小小的不足并没有算出物品装入后的重量,也没有展示最优解的价值为多少。

 

回溯法大作业报告

问题陈述:

在n×n格的棋盘上放置彼此不受攻击的n个皇后按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

要求在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。

回溯法基本思想:

从一条路往前走,能进则进,不能进则退回来,换一条路再试。

当我们遇到某一类问题时,它的问题可以分解,但是又不能得出明确的动态规划或是递归解法,此时可以考虑用回溯法解决此类问题。

回溯法的优点在于其程序结构明确,可读性强,易于理解,而且通过对问题的分析可以大大提高运行效率。

但是,对于可以得出明显的递推公式迭代求解的问题,还是不要用回溯法,因为它花费的时间比较长。

算法描述:

解向量:

(x1,x2,…,xn)

显约束:

xi=1,2,…,n

隐约束:

 1)不同列:

xi!

=xj

   2)不处于同一正、反对角线:

|i-j|!

=|x(i)-x(j)|

解空间:

满N叉树

  

程序代码:

#include

#include

usingnamespacestd;

classqueen

{

structq_place{

intx;

inty;

q_place()

:

x(0),y(0)

{}

};

public:

queen(intqc)

:

q_count(qc),sum_solution(0){

curr_solution.resize(q_count);

}

voidbacktrack(){

__backtrack(0);

}

private:

void__backtrack(intt){

if(t>=q_count){

++sum_solution;

for(size_ti=0;i

cout<<"x="<

<<"y="<

}

cout<<"解决方案有"<

}

else{

for(inti=0;i

curr_solution[t].x=i;

curr_solution[t].y=t;

if(__place(t)){

__backtrack(t+1);

}

}

}

}

bool__place(intk){

for(inti=0;i

if((abs(curr_solution[i].x-curr_solution[k].x)

==abs(curr_solution[i].y-curr_solution[k].y))

||curr_solution[i].x==curr_solution[k].x){

returnfalse;

}

}

returntrue;

}

private:

vectorcurr_solution;

constintq_count;

intsum_solution;

};

intmain()

{

inti;

cout<<"请输入皇后的个数:

"<

cin>>i;

queenq(i);

cout<<"各个皇后在不同位置时,对应的解决方案个数如下:

"<

q.backtrack();

return0;

}

运行结果:

结论分析:

n后问题主要在于可行解,一个一个的试,(t)能走通就往(t+1)下走,走不通就倒回去(t-1)换条走,再不行再回走。

就要不停的尝试,不停的回溯,直到找全可行解,或者一个也没有就停止。

还有重要的事约束条件,两个皇后不能在同行同列或者斜线上。

这题需要理解程序设计的顺序结构基本思想,掌握顺序结构语句特点。

并且学会用算法分析问题,能够使用顺序结构编写简单的程序解决具体问题。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1