算法分析与设计.docx

上传人:b****5 文档编号:5335836 上传时间:2022-12-15 格式:DOCX 页数:18 大小:27.66KB
下载 相关 举报
算法分析与设计.docx_第1页
第1页 / 共18页
算法分析与设计.docx_第2页
第2页 / 共18页
算法分析与设计.docx_第3页
第3页 / 共18页
算法分析与设计.docx_第4页
第4页 / 共18页
算法分析与设计.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

算法分析与设计.docx

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

算法分析与设计.docx

算法分析与设计

1.利用数组实现原始信息与处理结果的对应存储。

编程统计身高(单位为厘米)。

统计分150——154;155——159;160——164;165——169;170——174;175——179及低于是150、高于是179共八档次进行。

考虑关系式身高/5-29与数组小标的对应关系

#include

intmain()

{

inti,sg,a[8];

for(i=0;i<=7;i=i+1)

a[i]=0;

printf("inputheightdatauntilinput-1\n");

scanf("%d",&sg);

while(sg!

=-1)

{if(sg>179)a[7]=a[7]+1;

elseif(sg<150)a[0]=a[0]+1;

elsea[sg/5-29]=a[sg/5-29]+1;

scanf("%d",&sg);

}

for(i=0;i<=7;i=i+1)

printf("%dfieldthenumberofpeople:

%d\n",i+1,a[i]);

return0;

}

2.二维趣味矩阵的应用

练习:

编程打印形如下规律的n*n方阵。

例如下图:

使左对角线和右对角线上的元素为0,它们上方的元素为1,左方的元素为2,下方元素为3,右方元素为4,下图是一个符合条件的阶矩阵。

01110

20104

22044

20304

03330

主对角线元素i=j;

副对角线元素:

下标下界为1时i+j=n+1,

下标下界为0时i+j=n-1;

主上三角◥元素:

i<=j;

主下三角◣元素:

i>=j;

次上三角◤元素:

下标下界为1时i+j<=n+1,

下标下界为0时i+j<=n-1;

次下三角◢元素:

下标下界为1时i+j>=n+1,

下标下界为0时i+j>=n-1;

#include

intmain()

{inti,j,a[100][100],n;

scanf("%d",&n);

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

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

{if(i==j||i+j==n+1)a[i][j]=0;

if(i+j

if(i+jj)a[i][j]=2;

if(i+j>n+1&&i>j)a[i][j]=3;

if(i+j>n+1&&i

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

{

printf("\n");

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

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

printf("\n");}

return0;}

3.算法优化技巧中算术运算的妙用。

练习:

开灯问题:

有从1到n依次编号的n个同学和n盏灯。

1号同学将所有的灯都关掉;2号同学将编号为2的倍数的灯都打开;3号同学则将编号为3的倍数的灯作相反处理(该号灯如打开的,则关掉;如关闭的,则打开);以后的同学都将自己编号的倍数的灯,作相反处理。

问经n个同学操作后,哪些灯是打开的?

#include

intmain()

{intn,a[1000],i,k;

printf("inputanumber:

\n");

scanf("%d",&n);

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

a[i]=0;

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

{k=1;

while(i*k<=n)

{a[i*k]=1-a[i*k];

k=k+1;}

}

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

printf("%4d\n",a[i]);

return0;

}

4.非数值问题的处理

练习:

警察局抓了a,b,c,d四名偷窃嫌疑犯,其中只有一人是小偷。

审问中的描述如下:

a说:

“我不是小偷。

b说:

“c是小偷。

c说:

“小偷肯定是d。

d说:

“c在冤枉人。

现在已经知道四个人中三人说的是真话,一人说的是假话,问到底谁是小偷?

提示:

将以上信息数字化,用变量x存放小偷的编号,则x的取值范围从1取到4,就假设了他们中的某人是小偷的所有情况。

四个人所说的话就可以分别写成:

a说的话:

x<>1

b说的话:

x=3

c说的话:

x=4

d说的话:

x<>4或not(x=4)

#include

intmain()

{intx;

for(x=1;x<=4;x++)

{

if((x!

=1)+(x==3)+(x==4)+(x!

=4)==3)

printf("%cisathief.\n",x+64);

}

return0;

}

运行结果:

cisathief.

5.数学模型的应用

练习2:

求n次二项式各项的系数:

已知二项式的展开式为:

,要求利用杨辉三角形的规律来求解此问题。

各阶多项式的系数呈杨辉三角形的规律,因此可利用杨辉三角形的规律来编程实现。

(a+b)01

(a+b)11 1

(a+b)2 1 2 1

(a+b)31 331

(a+b)414641

(a+b)5……

则求n次二项式的系数的数学模型就是求n阶杨辉三角形。

算法设计要点:

除了首尾两项系数为1外,当n>1时,(a+b)n的中间各项系数是(a+b)n-1的相应两项系数之和,如果把(a+b)n的n+1的系数列为数组c,则除了c

(1)、c(n+1)恒为1外,设(a+b)n的系数为c(i),(a+b)n-1的系数设为c’(i)。

则有:

c(i)=c’(i)+c’(i-1)

而当n=1时,只有两个系数c

(1)和c

(2)(值都为1)。

不难看出,对任何n,(a+b)n的二项式系数可由(a+b)n-1的系数求得,直到n=1时,两个系数有确定值,故可写成递归子算法。

#include

voidcoeff(inta[],intn);

voidcoeff(inta[],intn)

{inti;

if(n==0)a[1]=1;

elseif(n==1)

{a[1]=1;

a[2]=1;}

else

{coeff(a,n-1);

a[n+1]=1;

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

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

a[1]=1;

}

}

intmain()

{inta[100]={0},i,n;

scanf("%d",&n);

coeff(a,n);

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

printf("%4d",a[i]);

printf("\n");

return0;

}

6.分治算法的应用

练习3:

求数列的最大子段和。

给定n个整数(可能为负整数)组成的序列a1,a2,...,an,求该序列连续的子段,使其和为最大。

如果该序列的所有元素都是负整数时定义其最大子段和为0。

对于此问题可采用二分法逐步分解来完成。

算法的设计思想如下:

将所给的序列a[1..n]分为长度相等的2段a[1—(n/2)]和a[(n/2)+1—n],分别求出这2段的最大子段和,则a[1.n]的最大子段和有3种情形。

1)a[1..n]的最大子段和与a[1..(n/2)]的最大子段和相同;

2)a[1..n]的最最大子段和与a[(n/2)+1..n]的最大子段和相同;

3)a[1..n]的最大子段和为a[i:

j],且1≤i≤(n/2),(n/2)+1≤j≤n。

情况1)和情况2)可分别递归求得。

对于情况3),a[(n/2)]与a[(n/2)+1]一定在最大子段中,因此可以以(n/2)为中心,分次求出i:

(n/2),(n/2)+1:

j两子段的和,并相加返回。

#include

intmaxSubSum(inta[],intleft,intright)

{

inti,j,sum=0;

if(left==right)//这是递归调用必须要有的终值情况。

{

sum=(a[left]>0?

a[left]:

0);

}

else

{

intcenter=(left+right)/2;

intleftSum=maxSubSum(a,left,center);//求出左序列最大子段和

intrightSum=maxSubSum(a,center+1,right);//求出右序列最大子段和

//求跨前后两段的情况,从中间分别向两端扩展。

从中间向左扩展。

这里注意,中间往左的第一个必然包含在内。

intls=0;intlefts=0;

inttempi=center,tempj=center+1;

for(i=center;i>=left;i--)

{

lefts+=a[i];

if(lefts>ls)

ls=lefts;

}

intrs=0;intrights=0;

for(j=++center;j<=right;j++)

{

rights+=a[j];

if(rights>rs)

rs=rights;

}

sum=ls+rs;//sum保存跨前后两段情况的最大子段和求跨前后两段的情况完成

if(sum

sum=leftSum;//记住,leftSum表示前段序列的最大子段和

if(sum

sum=rightSum;//rightSum表示后段序列的最大字段和

}

returnsum;

}

voidmain()

{inta[5]={8,-2,9,10,-4};

intd=maxSubSum(a,0,4);

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

}

7.算法基本技巧的应用

练习1:

楼梯上有n阶台阶,上楼可以一步上1阶,也可以一步上2阶,编写算法计算共有多少种不同的上楼梯方法。

算法的设计思想:

此问题如果按照习惯,从前向后思考,也就是从第一阶开始,考虑怎么样走到第二阶、第三阶、第四阶……,则很难找出问题的规律;而反过来先思考“到第n阶有哪几种情况?

”,答案就简单了,只有两种情况:

1) 从第n-1阶到第n阶;

2) 从第n-2阶到第n阶。

记n阶台阶的走法数为f(n),则

  f(n)=1n=1

f(n)=2n=2

f(n-1)+f(n-2)n>2

算法可以用递归完成,下面是问题的递归算法。

intmain()

{

intn,fn;

printf('n=');

scanf("%d",&n);

fn=f(n);

}

intf(intx)

{

if(x==1)return

(1);

if(x==2)return

(2);

else

return(f(x-1)+f(x-2));

}

8.贪婪算法应用

练习2:

问题描述:

  今天张麻子打算去约会。

大家都知道张麻子是超级大帅哥,所以和他约会的MM也超级多,她们每个人都和张麻子订了一个约会时间。

但是今天张麻子刚打算出门的时候才发现,某几个MM的约会时间有冲突。

由于张麻子不会分身,还不能和多个MM同时约会,他只能忍痛割爱拒绝掉某些MM。

但是张麻子这个花心大萝卜还是不死心,他想知道,他最多可以和多少个MM约会。

  

输入:

  输入的第一行包含一个正整数N(0

接下去N行,每行描述一个MM,格式为:

Namestarttimeendtime,表示在[starttime,endtime)这个半开区间是这个MM的约会时间,starttime

名字由大写或小写字母组成,最长不超过15个字母,保证没有两个人拥有相同的名字,所有时间采用24小时制,格式为XX:

XX,且在06:

00到23:

00之间。

输出:

  输出的第一行是一个整数M表示张麻子最多可以和多少个MM约会。

接下来那一行就是M个MM的名字,用空格隔开。

您可以按照任意的顺序输出。

如果存在多个答案,您可以任选一个输出。

 

输入示例:

4

Lucy06:

0010:

00

Lily10:

0017:

00

HanMeimei16:

0021:

00

Kate11:

0013:

00

 

输出示例:

3

LucyKateHanMeimei

 

算法分析:

典型的任务选择问题,可先按完成时间排序然后贪心选择,即在可能的事件a1

编程要点:

1、谁结束时间早就选谁,因此要排序;

2、进行选择时,还要考虑前一个被选人的结束时间与后一个开始时间是否有重叠。

#include

#include

#include

#include

usingnamespacestd;

structgirl

{

charname[20];

intfirst,second;//约会的开始时间与结束时间

};

//此段函数即为sort函数对girl排序所用的排序规则,

//贪心算法为尽可能多地选择约会,因此要先对约会结束时间段按升序排列,

//但有可能结束时间相等的,则考虑谁开始早谁排在前面,否则谁结束早谁排在前面。

boolcmp(girla,girlb)

{

if(a.second==b.second)

returna.first

returna.second

}

intmain()

{

inti,n,hour,min;

charaa;

girlgf[1000];

stringstr[1000];

scanf("%d",&n);

for(i=0;i

{

scanf("%s%d%c%d",&gf[i].name,&hour,&aa,&min);

gf[i].first=hour*60+min;

scanf("%d%c%d",&hour,&aa,&min);

gf[i].second=hour*60+min;

}

sort(gf,gf+n,cmp);//对MM排序,sort为C++的函数,使用要包括头文件

//要求sort使用cmp规则来对gf结构体数组排序

str[0]=gf[0].name;

intcount=1;

girltemp=gf[0];

for(i=1;i

{

if(gf[i].first>=temp.second)

{

str[count++]=gf[i].name;

temp=gf[i];

}

}

cout<

for(i=0;i

cout<

return0;

}

9.动态规划算法求解数塔问题

有形如图4-1所示的一个数塔,从顶部出发,在每一结点可以选择向左走或是向右走,一直走到底层,要求找出一条路径,使路径上的数值和最大。

 

程序参考:

#include

main()

{

intdata[50][50];//存储原始信息

intdecision[50][50];//存储决策信息

/**数组path[i][j]存储data[i][j]选择路径,

取值为0表示向左取值为1表示向右

*/

intpath[50][50];

inti,j,n;

/**输入数塔有多少行*/

printf("pleaseinputthenumberofrows:

");

scanf("%d",&n);

/**输入初始数据*/

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

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

{

/**输入数塔中的数据*/

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

/**初始决策信息与原始数塔数据相同*/

decision[i][j]=data[i][j];

/**置选择路径的初始值为0*/

path[i][j]=0;

}

 

/**动态规划过程的存储*/

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

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

{

/**左结合*/

if(decision[i+1][j]>decision[i+1][j+1])

{

decision[i][j]=decision[i+1][j]+decision[i][j];

path[i][j]=0;

}

/**右结合*/

else

{

decision[i][j]=decision[i+1][j+1]+decision[i][j];

path[i][j]=1;

}

}

/**动态规划过程结束decision[1][1]为最大值*/

printf("max=%d\n",decision[1][1]);

/**根据path[i][j]找出最优解路径*/

j=1;

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

{

printf("%d->",data[i][j]);

j=j+path[i][j];

}

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

}

 

10.求两个字符序列的最长公共字符子序列。

算法分析:

设A=“a0,a1,…,am-1”,

B=“b0,b1,…,bn-1”,

Z=“z0,z1,…,zk-1”为它们的最长公共子序列。

有以下结论:

1)如果am-1=bn-1,则zk-1=am-1=bn-1,且“z0,z1,…,zk-2”是“a0,a1,…,am-2”和“b0,b1,…,bn-2”的一个最长公共子序列;

2)如果am-1≠bn-1,则若zk-1≠am-1,蕴涵“z0,z1,…,zk-1”是"a0,a1,…,am-2"和"b0,b1,…,bn-1"的一个最长公共子序列;

3)如果am-1≠bn-1,则若zk-1≠bn-1,蕴涵“z0,z1,…,zk-1”是“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一个最长公共子序列。

定义c[i][j]为序列a0,a1,…,ai-2”和“b0,b1,…,bj-1”的最长公共子序列的长度,计算c[i][j]可递归地表述如下:

1)c[i][j]=0如果i=0或j=0;

2)c[i][j]=c[i-1][j-1]+1如果i,j>0,且a[i-1]=b[j-1];

3)c[i][j]=max(c[i][j-1],c[i-1][j])如果i,j>0,且a[i-1]≠b[j-1]。

参考程序:

#include

#include

chara[100],b[100],str[100];

intc[100][100];

intlcs_len(inti,intj)

{

intt1,t2;

if(i==0||j==0)

c[i][j]=0;

else

{

if(a[i-1]==b[j-1])

c[i][j]=lcs_len(i-1,j-1)+1;

else

{

t1=lcs_len(i,j-1);

t2=lcs_len(i-1,j);

if(t1>t2)

c[i][j]=t1;

else

c[i][j]=t2;

}

}

returnc[i][j];

}

voidbuild_lcs(intk,inti,intj)

{

if(i==0||j==0)

return;

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

build_lcs(k,i-1,j);

else

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

build_lcs(k,i,j-1);

else

{

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

build_lcs(k-1,i-1,j-1);

}

}

voidmain()

{

intm,n,k;

printf("Entertwostring!

\n");

gets(a);

gets(b);

m=strlen(a);

n=strlen(b);

k=lcs_len(n,m);

build_lcs(k,n,m);

puts(str);

}

11.求最长不降子序列。

设有由n个不相同的整数组成的数列,记为:

a

(1)、a

(2)、……、a(n)且a(i)<>a(j)(i<>j)

若存在i1

请求出一个数列的最长不下降序列。

参考程序:

#include

inta[100],b[100],c[100];

main()

{

intn,i,j,max,p;

scanf("%d",&n);

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

{

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

b[i]=1;

c[i]=0;

}

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

{

max=0;

p=0;

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

if(a[i]max)

{

max=b[j];

p=j;

}

if(p!

=0)

{

b[i]=b[p]+1;

c[i]=p;

}

}

max=0;

p=0;

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

if(b[i]>max)

{

max=b[i];

p=i;

}

printf("maxlong=%d\n",max);

printf("resultis:

");

while(p!

=0)

{

printf("%5d",a[p]);

p=c[p];

}

}

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

当前位置:首页 > 高等教育 > 艺术

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

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