完整word版算法实验word文档良心出品.docx

上传人:b****7 文档编号:26525901 上传时间:2023-06-20 格式:DOCX 页数:15 大小:64.18KB
下载 相关 举报
完整word版算法实验word文档良心出品.docx_第1页
第1页 / 共15页
完整word版算法实验word文档良心出品.docx_第2页
第2页 / 共15页
完整word版算法实验word文档良心出品.docx_第3页
第3页 / 共15页
完整word版算法实验word文档良心出品.docx_第4页
第4页 / 共15页
完整word版算法实验word文档良心出品.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

完整word版算法实验word文档良心出品.docx

《完整word版算法实验word文档良心出品.docx》由会员分享,可在线阅读,更多相关《完整word版算法实验word文档良心出品.docx(15页珍藏版)》请在冰豆网上搜索。

完整word版算法实验word文档良心出品.docx

完整word版算法实验word文档良心出品

递归与分治策略

①问题描述:

给定数组a[0:

n-1],试设计一个算法,在最坏情况下用[3n/2-2]次比较找出a[0:

n-1]中元素的最大值和最小值。

解决方法:

先将数组前一半的元素与后一半的元素分别逐个进行比较,如第1个与第n/2+1个,将较小者在前较大者在后交换好,则通过n/2次比较后最大值在后一半,最小值在前一半;然后在前一半与后一半中分别经过n/2-1次比较得到最大值与最小值。

整个算法经过n/2+2*(n/2-1)=3/2*n-2次比较。

代码实现:

#include

intmain()

{

intmax,min;

inti,n,t;

inta[100];

scanf("%d",&n);

for(i=0;i

scanf("%d",&a[i]);

for(i=0;i

if(a[i]>a[n/2+i]){

t=a[i];

a[i]=a[n/2+i];

a[n/2+i]=t;

}

max=a[n-1];

min=a[0];

for(i=1;i

if(min>a[i])min=a[i];

for(i=n-1;i>=n/2;i--)

if(max

printf("themaxis%d\n",max);

printf("theminis%d\n",min);

return0;

}

运行截图:

实验心得:

本实验要点在于运用分治法的思想,将N个数之间的问题分割成一些小规模的相同问题,以便减少计算的复杂度。

 

②问题描述:

Gray码是一个长度为2^n的序列。

序列中无相同元素,每个元素都是长度为n位的串,相邻元素恰好只有一位不同。

用分治策略设计一个算法对任意的n构造相应的Gray码。

解决方法:

当n=1时,Gray码:

0,1

当n=2时,Gray码:

00,10,11,01

当n=3时,Gray码:

000,010,011,001,101,111,110,100

当n=4时,Gray码:

0000,0010,0011,0001,0101,0111,

0110,0100,1100,1110,1111,1101,

1001,1011,1010,1000

······

可以看出,从n=2开始,每个n的Gray码由两部分组成。

后一位的Gray码可以从前一位的Gray码求出。

即在n的Gray码的前半部分是n-1的所有Gray码顺次在前面加0得到;n的Gray码的后半部分是n-1的所有Gray码逆序在前面加1得到。

代码实现:

#include

intstr[100000][40];

intn;

intf(intx)

{

inty=1;

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

y*=2;

returny;

}

voidgray(inta,intb)

{

if(b==0)return;

for(inti=0;i

{

str[i][n-b]=0;

str[i+a/2][n-b]=1;

}

gray(a/2,b-1);

for(inti=a/2;i

for(intj=n-b+1;j

str[i][j]=str[a-i-1][j];

}

intmain()

{

while(scanf("%d",&n),n)

{

gray(f(n),n);

for(inti=0;i

for(intj=0;j

printf("%d",str[i][j]);

printf("\n");

}

return0;

}

运行截图:

实验心得:

本实验要点是对Gray(inta,intb)递归调用,着重后一半的逆序在前面加1.递归的使用使得程序简短明了。

动态规划

③问题描述:

在一个圆形操场的四周摆放着n堆石子,现要将石子有次序地合并成一堆。

规定每次只能选相邻的两堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。

试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。

解决方法:

将圆形断开得

a[i]i=j

Max[i][j]={a[i]+a[j]i=j-1

Max[i][k]+max[k+1][j]+a[i]+a[i+1]+···+a[j]i

a[i]i=j

Min[i][j]={a[i]+a[j]i=j-1

Min[i][k]+min[k+1][j]+a[i]+a[i+1]+···+a[j]i

用动规自底向上计算。

代码实现:

#include

#defineinf100000000

inta[1000],sum[1000];

intn;

intdp[1000][1000][2];

intmain()

{

inti,j,k,h;

while(scanf("%d",&n)!

=EOF)

{

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

scanf("%d",&a[i]);

intamin=inf;

intamax=-inf;

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

{

sum[0]=0;

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

sum[i]=sum[i-1]+a[i];

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

dp[i][i][0]=dp[i][i][1]=0;

for(i=1;i

dp[i][i+1][0]=dp[i][i+1][1]=a[i]+a[i+1];

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

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

{

intnmin=inf;

intnmax=-inf;

for(k=i;k<=i+j-2;k++)

{

if(nmin>dp[i][k][0]+dp[k+1][i+j-1][0]+sum[j+i-1]-sum[i-1])nmin=dp[i][k][0]+dp[k+1][i+j-1][0]+sum[j+i-1]-sum[i-1];

if(nmax

}

dp[i][i+j-1][0]=nmin;

dp[i][i+j-1][1]=nmax;

}

if(amin>dp[1][n][0])amin=dp[1][n][0];

if(amax

a[n+1]=a[1];

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

a[i]=a[i+1];

}

printf("theminvalueis%d\n",amin);

printf("themaxvalueis%d\n",amax);

}

return0;

}

运行截图:

实验心得:

本实验用动态规划方法求解,关键在于先找出直线排列的最优解,然后再刻画圆排列时的最优解,在计算中保存已经计算过的结果,每个子问题只计算一次,从而避免大量的计算。

 

④问题描述:

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,···,n。

游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。

游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i

试设计一个算法,计算出从游艇出租站i到游艇出租站j所需的最少租金。

解决方法:

用dp[i][j]表示从i到j的最小费用

dp[i][j]=r[i][j]j-i=1

{

dp[i][j]=min(r[[i][j],min(dp[i][k]+dp[k][j]j-i>1,i

代码实现:

#include

#defineinf100000000

intr[100][100];

intdp[100][100];

intn;

intmain()

{

inti,j,k;

scanf("%d",&n);

for(i=1;i

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

scanf("%d",&r[i][j]);

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

dp[i][i]=0;

for(i=1;i

dp[i][i+1]=r[i][i+1];

for(k=3;k<=n;k++)

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

{

dp[i][i+k-1]=r[i][i+k-1];

for(j=i+1;j<=i+k-2;j++)

if(dp[i][i+k-1]>dp[i][j]+dp[j][i+k-1])

dp[i][i+k-1]=dp[i][j]+dp[j][i+k-1];

}

while(scanf("%d%d",&i,&j)!

=EOF)

printf("%d\n",dp[i][j]);

return0;

}

运行截图:

实验心得:

本实验运用动态规划方法,由原先构造好的最优解结构编程实现,减小计算量。

贪心算法

⑤问题描述:

利用优先队列及并查集这两个抽象数据类型实现Kruskal算法。

解决方法:

首先将n个顶点看成n个孤立的连通分支,利用优先队列将所有边按权从小到大排列。

然后从第一条边开始,依边权递增的顺序查看每一条边,若该边的两个顶点分属于不同分支,则用边将其连起来,否则看下一条。

用到集合的查找与合并,即并查集数据类型。

代码实现:

#include

#defineMAX_TREE_SIZE100

typedefstructPTNode{//树的双亲表示

intdata;

intparent;

}PTNode;

typedefstruct{

PTNodenodes[MAX_TREE_SIZE];

intn;

}PTree;

typedefPTreeMFSet;//并查集

intinit_mfset(MFSetS){

}

intfind_mfset(MFSetS,inti){

if(i<1||i>S.n)return-1;

intj;

for(j=i;S.nodes[j].parent>0;j=S.nodes[j].parent);

returnj;

}

intmerge_mfset(MFSet&S,inti,intj){

if(i<1||i>S.n||j<1||j>S.n)

return-1;

if(S.nodes[i].parent>S.nodes[j].parent){

S.nodes[j].parent+=S.nodes[i].parent;

S.nodes[i].parent=j;

}

else{

S.nodes[i].parent+=S.nodes[j].parent;

S.nodes[j].parent=i;

}

return1;

}//"mfset.h"

 

#include

#include"mfset.h"

#include

usingnamespacestd;

structbian

{

doubleweight;

intu,v;

friendbooloperator<(biann1,biann2)

{

returnn1.weight>n2.weight;

}

}edge[100];

biant[100];

intn,e,k;

voidkruskal()

{

priority_queueQ;

for(inti=0;i

Q.push(edge[i]);

MFSetS;

S.n=n;

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

S.nodes[i].parent=0;

k=0;

while(!

Q.empty()&&k

{

bianx=Q.top();

Q.pop();

inta=find_mfset(S,x.u);

intb=find_mfset(S,x.v);

if(a!

=b)

{

t[k++]=x;

merge_mfset(S,a,b);

}

}

}

intmain()

{

scanf("%d%d",&n,&e);

for(inti=0;i

scanf("%d%d%lf",&edge[i].u,&edge[i].v,&edge[i].weight);

kruskal();

for(inti=0;i

printf("%d->%d%.3lf\n",t[i].u,t[i].v,t[i].weight);

}

运行截图:

实验心得:

本实验为使代码简洁将并查集代码写到了"mfset.h"作为头文件使用,利用优先队列简单地实现了排序。

用贪心的方法实现了Kruskal算法最小生成树。

 

回溯法

⑥问题描述:

试设计一个解子集和问题的递归回溯法。

注意对于子集和问题,一旦找到和为c的子集,算法即可终止。

算法中不必记录当前最优解,也不必用数组x记录当前路径。

问题的解可在找到和为c的子集后重新构造。

解决方法:

用子集树递归回溯的方法,1为取,0为不取,一个叶子一个叶子找,找到一组符合元素和为c便停止。

代码实现:

#include

ints,a[1000],n,c;

intback(inti)

{

if(i==n)

{

if(s==c)return1;

elsereturn0;

}

if(s+a[i]<=c)

{

s=s+a[i];

if(back(i+1))return1;

s=s-a[i];

}

if(back(i+1))return1;

return0;

}

intmain()

{

inti;

scanf("%d",&n);

for(i=0;i

scanf("%d",&a[i]);

scanf("%d",&c);

s=0;

if(back(0))printf("有子集和为%d的子集。

\n",c);

elseprintf("无子集和为%d的子集。

\n",c);

}

运行截图:

实验心得:

本实验运用回溯法实现,约束条件是子集和为C,一旦找到即可终止,过程中也不需要作记录,因此只要按照条件搜索到就行。

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

当前位置:首页 > 医药卫生 > 基础医学

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

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