九种基本算法概论.docx
《九种基本算法概论.docx》由会员分享,可在线阅读,更多相关《九种基本算法概论.docx(23页珍藏版)》请在冰豆网上搜索。
九种基本算法概论
九种基本算法思想
一、枚举算法
1、基本思想
枚举法也叫穷举算法,是指将问题的所有可能的结果一一列举,然后根据条件判断是否适合,适合就保留,不是喝酒舍弃;一般采用while循环实现。
2、实例演练
百钱买百鸡问题:
公鸡每只5元,母鸡每只3元,小鸡3元一只。
先用100元钱,买公鸡、母鸡、小鸡各几只?
代码:
#include
intmain()
{
intx,y,z;
for(x=0;x<=20;x++)
{
for(y=0;y<=33;y++)
{
z=100-x-y;
if(z%3==0&&x*5+y*3+z/3==100)
printf("公鸡:
%d,母鸡:
%d,小鸡:
%d\n",x,y,z);
}
}
getch();
return0;
}
二、递推算法
1、算法思想:
具体分两种:
(1)顺推法:
从已知条件入手,逐步推算出要解决问题的方法。
例如斐波那契数列;
(2)逆推法:
从已知的结果出发,利用迭代表达式逐步推算出问题开始的条件;
2.实例演练:
(1)斐波那契数列(兔子的繁殖):
代码:
#include
#defineNUM13
intmain()
{
inti;
longfib[NUM]={1,1};
for(i=2;i{
fib[i]=fib[i-1]+fib[i-2];
}
for(i=0;i{
printf("%d月兔子总数:
%d\n",i,fib[i]);
}
getch();
return0;
}
(2)母亲为儿子大学四年生活费存了一笔钱,方式是整存零取,规定儿子每月月底取走下月的生活费1000元。
现在假设银行的年利率是1.71%,现在计算母亲至少存多少钱?
代码:
#include
#defineFETCH1000
#defineRATE0.0171
intmain()
{
doublecorpus[49];
inti;
corpus[48]=(double)FETCH;
for(i=47;i>0;i--)
{
corpus[i]=(corpus[i+1]+FETCH)/(1+RATE/12);
}
for(i=48;i>0;i--)
{
printf("第%d月末本利合计:
%.2f\n",i,corpus[i]);
}
getch();
return0;
}
三、递归算法
1.算法思想:
就是函数自己调用自己的算法;
2.实例演练:
(1)汉诺塔问题:
代码:
move(intn,intx,inty,intz)
{
if(n==1)
printf("%c-->%c\n",x,z);
else
{
move(n-1,x,z,y);
printf("%c-->%c\n",x,z);
{getchar();}
move(n-1,y,x,z);
}
}
main()
{
inth;
printf("inputnumber:
");
scanf("%d",&h);
printf("thesteptomoving%2ddiskes:
\n",h);
move(h,'a','b','c');
system("pause");
}
(2)阶乘问题:
代码:
#include
intfact(intn);
intmain()
{
inti;
printf("请输入要求阶乘的一个整数:
");
scanf("%d",&i);
printf("%d的阶乘结果为:
%d\n",i,fact(i));
getch();
return0;
}
intfact(intn)
{
if(n<=1)
return1;
else
returnn*fact(n-1);
}
四、分治算法
1.算法思想:
将一个规模为N的问题分解为K个规模较小的问题,这些问题相互独立且与原问题性质相同,我们只需要求出每个子问题的结果就可以得到原问题的结果。
2.实例演练:
大数相乘问题:
#include
#include
#include
#include
char*result='\0';
intpr=1;
voidgetFill(char*a,char*b,intia,intja,intib,intjb,inttbool,intmove){
intr,m,n,s,j,t;
char*stack;
m=a[ia]-48;
if(tbool){//直接从结果数组的标志位填入,这里用了堆栈思想
r=(jb-ib>ja-ia)?
(jb-ib):
(ja-ia);
stack=(char*)malloc(r+4);
for(r=j=0,s=jb;s>=ib;r++,s--){
n=b[s]-48;
stack[r]=(m*n+j)%10;
j=(m*n+j)/10;
}
if(j){
stack[r]=j;
r++;
}
for(r--;r>=0;r--,pr++)
result[pr]=stack[r];
free(stack);
for(move=move+pr;prresult[pr]='\0';
}
else{//与结果的某几位相加,这里不改变标志位pr的值
r=pr-move-1;
for(s=jb,j=0;s>=ib;r--,s--){
n=b[s]-48;
t=m*n+j+result[r];
result[r]=t%10;
j=t/10;
}
for(;j;r--){
t=j+result[r];
result[r]=t%10;
j=t/10;
}
}
}
intget(char*a,char*b,intia,intja,intib,intjb,intt,intmove){
intm,n,s,j;
if(ia==ja){
getFill(a,b,ia,ja,ib,jb,t,move);
return1;
}
elseif(ib==jb){
getFill(b,a,ib,jb,ia,ja,t,move);
return1;
}
else{
m=(ja+ia)/2;
n=(jb+ib)/2;
s=ja-m;
j=jb-n;
get(a,b,ia,m,ib,n,t,s+j+move);
get(a,b,ia,m,n+1,jb,0,s+move);
get(a,b,m+1,ja,ib,n,0,j+move);
get(a,b,m+1,ja,n+1,jb,0,0+move);
}
return0;
}
intmain(){
char*a,*b;
intn,flag;
a=(char*)malloc(1000);
b=(char*)malloc(1000);
printf("Theprogramwillcomputera*b\n");
printf("Enterab:
");
scanf("%s%s",a,b);
result=(char*)malloc(strlen(a)+strlen(b)+2);
flag=pr=1;
result[0]='\0';
if(a[0]=='-'&&b[0]=='-')
get(a,b,1,strlen(a)-1,1,strlen(b)-1,1,0);
if(a[0]=='-'&&b[0]!
='-'){
flag=0;
get(a,b,1,strlen(a)-1,0,strlen(b)-1,1,0);
}
if(a[0]!
='-'&&b[0]=='-'){
flag=0;
get(a,b,0,strlen(a)-1,1,strlen(b)-1,1,0);
}
if(a[0]!
='-'&&b[0]!
='-')
get(a,b,0,strlen(a)-1,0,strlen(b)-1,1,0);
if(!
flag)
printf("-");
if(result[0])
printf("%d",result[0]);
for(n=1;nprintf("%d",result[n]);
printf("\n");
free(a);
free(b);
free(result);
system("pause");
return0;
}
五、贪心算法
1.算法思想:
也叫贪婪法。
在求解问题时总是做出在当下看来是最好的抉择的方法。
2.实例演练
(1)人民币找零问题:
#include
#defineMAXN9
intparvalue[MAXN]={10000,5000,2000,1000,500,100,50,10};
intnum[MAXN]={0};
intexchange(intn)
{
inti,j;
for(i=0;iif(n>parvalue[i])break;//找到比n小的最大面额
while(n>0&&i{
if(n>=parvalue[i])
{
n-=parvalue[i];
num[i]++;
}elseif(n<10&&n>=5)
{
num[MAXN-1]++;
break;
}elsei++;
}
return0;
}
intmain()
{
inti;
floatm;
printf("请输入找零的金额:
");
scanf("%f",&m);
exchange((int)100*m);
printf("\n%.2f元零钱的组成:
\n",m);
for(i=0;iif(num[i]>0)
printf("%6.2f:
%d张\n",(float)parvalue[i]/100.0,num[i]);
getch();
return0;
}
(3)装箱问题:
#include
#include
#defineN6
#defineV100
typedefstructbox
{
intno;
intsize;
structbox*next;
}BOX;
voidinit_list(BOX**H)
{
*H=(BOX*)malloc(sizeof(BOX));
(*H)->no=0;
(*H)->size=0;
(*H)->next=NULL;
}
BOX*find_p(BOX*H,intvolume,intv)
{
BOX*p=H->next;
while(p!
=NULL)
{
if(p->size+volume<=v)
break;
p=p->next;
}
returnp;
}
voidadd_list_tail(BOX*H,BOX*p)
{
BOX*tmp=H->next;
BOX*q=H;
while(tmp!
=NULL)
{
q=tmp;
tmp=tmp->next;
}
q->next=p;
}
voidprint_list(BOX*H)
{
BOX*p=H->next;
while(p!
=NULL)
{
printf("%d:
%d\n",p->no,p->size);
p=p->next;
}
}
intadd_box(intvolume[],intv)
{
intcount=0;
inti;
BOX*H=NULL;
init_list(&H);
for(i=0;i{
BOX*p=find_p(H,volume[i],v);
if(p==NULL)
{
count++;
p=(BOX*)malloc(sizeof(BOX));
p->no=count;
p->size=volume[i];
p->next=NULL;
add_list_tail(H,p);
}
else
{
p->size+=volume[i];
}
}
print_list(H);
returncount;
}
intmain(intargc,char*argv[])
{
intret;
intvolumes[]={60,45,35,20,20,20};
ret=add_box(volumes,V);
printf("%d\n",ret);
system("PAUSE");
return0;
}
六、动态规划
1.算法思想:
是系统分析算法的一种常用算法,根据时空的特点,将复杂问题分成若干的小阶段,在选定系统上进行方向之后,逆向从终点开始计算,逐次对每个阶段寻找某种策略,使得整个过程达到最优。
通常分成两个阶段:
划分阶段;选择状态。
2.实例演练:
求两个字符串的最长公共子串:
#include
#include
#defineMAXLEN100
voidLCSLength(char*x,char*y,intm,intn,intc[][MAXLEN],intb[][MAXLEN])
{
inti,j;
for(i=0;i<=m;i++)
c[i][0]=0;
for(j=1;j<=n;j++)
c[0][j]=0;
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
if(x[i-1]==y[j-1])
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]=0;
}
elseif(c[i-1][j]>=c[i][j-1])
{
c[i][j]=c[i-1][j];
b[i][j]=1;
}
else
{
c[i][j]=c[i][j-1];
b[i][j]=-1;
}
}
}
}
voidPrintLCS(intb[][MAXLEN],char*x,inti,intj)
{
if(i==0||j==0)
return;
if(b[i][j]==0)
{
PrintLCS(b,x,i-1,j-1);
printf("%c",x[i-1]);
}
elseif(b[i][j]==1)
PrintLCS(b,x,i-1,j);
else
PrintLCS(b,x,i,j-1);
}
intmain(intargc,char**argv)
{
charx[MAXLEN]={"ABCBDAB"};
chary[MAXLEN]={"BDCABA"};
intb[MAXLEN][MAXLEN];
intc[MAXLEN][MAXLEN];
intm,n;
m=strlen(x);
n=strlen(y);
LCSLength(x,y,m,n,c,b);
PrintLCS(b,x,m,n);
getch();
return0;
}
七、试探算法
1.算法思想
又称回溯法,先暂且放弃关于问题规模大小的限制,并将问题的候选解按照某种次序逐一枚举和检验,当发现当前候选解不可能是正确解时就选择下一个候选解,若是,则扩大当前候选解的规模。
2.实例演练:
八皇后问题:
#include
#defineN8
intsolution[N],j,k,count,sols;
intplace(introw,intcol)
{
for(j=0;j{
if(row-j==solution[row]-solution[j]||row+solution[row]==j+solution[j]||solution[j]==solution[row])
return0;
}
return1;
}
voidbacktrack(introw)
{
count++;
if(N==row)
{
sols++;
for(k=0;kprintf("%d\t",solution[k]);
printf("\n\n");
}
else
{
inti;
for(i=0;i{
solution[row]=i;
if(place(row,i))
backtrack(row+1);
}
}
}
voidqueens()
{
backtrack(0);
}
intmain(void)
{
queens();
printf("TotalSolutions:
%d\n",sols);
getch();
return0;
}
八、迭代算法
1.算法思想:
也成辗转法。
不断用变量的旧值递推新值的算法;
2.实例演练:
求平方根:
#include
#include
voidmain()
{
doublea,x0,x1;
printf("Inputa:
\n");
scanf("%lf",&a);//为什么在VC6.0中不能写成“scanf("%f",&a);”?
if(a<0)
printf("Error!
\n");
else
{
x0=a/2;
x1=(x0+a/x0)/2;
do
{
x0=x1;
x1=(x0+a/x0)/2;
}while(fabs(x0-x1)>=1e-6);
}
printf("Result:
\n");
printf("sqrt(%g)=%g\n",a,x1);
getch();
return0;
}
九、模拟算法
1.算法思想:
模拟算法是最基本的算法,是根据题目的规则对题目进行编程模拟。
例如在C语言中使用srand()初始化随机数发生器,然后利用rand()函数来生成随机数。
2.实例演练:
(1)猜数游戏:
#include
#include
intmain()
{
intn,m,i=0;
srand(time(NULL));
n=rand()%100+1;
do{
printf("输入所猜数字:
");
scanf("%d",&m);
i++;
if(m>n)
printf("错误!
所猜数太大了!
\n");
elseif(mprintf("错误!
所猜数太小了!
\n");
}while(m!
=n);
printf("答对了!
\n");
printf("共猜测了%d次。
\n",i);
if(i<=5)
printf("你太聪明了,这么快就猜出来了!
");
elseif(i>5)
printf("还需改进方法,以便更快猜出来!
");
getch();
return0;
}
(2)掷骰子游戏:
#include
#include
voidplay(intn)
{
inti,m=0,t=0;
for(i=0;i{
t=rand()%6+1;
m+=t;
printf("\t第%d粒:
%d;\n",i+1,t);
}
printf("\t总点数为:
%d\n",m);
}
intmain(void)
{
intc;//参赛人数
intn;//骰子数量
inti,m;
do{
srand(time(NULL));
printf("设置骰子数量(输入0退出):
");
scanf("%d",&n);
if(n==0)break;//至少一个骰子
printf("\n输入本轮参赛人数(输入0退出):
");
scanf("%d",&c);
if(c==0)break;
for(i=0;i{
printf("\n第%d位选手掷出的骰子为:
\n",i+1);
play(n);
}
printf("\n");
}while
(1);
return0;
}
|