6月4日下午刚睡完午觉,下午没课赶紧把递归搞完吧,看情况状态好再打点贪心,多留时间给DP毕竟那才是重头,10号前应该能完成,祝看过此博客的期末都AK~
题目传送门
4-1计算组合数
很无脑的题,题目让你干啥你就干啥呗,表达式写出来就行了,计算都是电脑的事情,递归就是这么暴力。
#include <stdio.h>
#include <stdlib.h>
int c(int n,int m)
{
if(m==0||n==1||m==n) return 1;
return c(n-1,m-1)+c(n-1,m);
}
int main()
{
int n,m,t;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
printf("%d\n",c(n,m));
}
return 0;
}
4-2神奇的函数
比上题还方便 伪代码都有了 复制粘贴微改一下就行
#include <stdio.h>
#include <stdlib.h>
int F(int n,int m) {
if (n == 1 || m == 1)
return 1;
else
return F(n-1, m) + F(n, m-1);
}
int main()
{
int n,m,t;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
printf("%d\n",F(n,m));
}
return 0;
}
4-3喵帕斯之天才算数少女
#include <stdio.h>
#include <stdlib.h>
int F(int m,int n) {
if ( m == 0)
return n+1;
else if(m>0&&n==0)
return F(m-1, 1);
else return F(m-1,F(m,n-1));
}
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
printf("%d\n",F(n,m));
}
return 0;
}
4-4汉诺塔
汉诺塔问题:
汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?
分析:
图片均引用自网络
先看n=3的汉诺塔:
如果再加一个盘:
可以如此模拟:
将上面过程一般化,我们定义三个柱子的类型分别为出发柱、目标柱、缓存柱,注意柱子类型是可以不断变化的。
那么把n个柱子从出发柱移动到目标柱分为三步骤:
1.把上面n-1个柱子从出发柱移动到缓存柱。
2.把第n个柱子移动到目标柱。
3.把缓存柱的n-1个柱子移动到目标柱。
其中,第一步的把n-1个柱子从出发柱移动到缓存柱也可以看成一次更小规模的汉诺塔,即原来的缓存柱变成了目标柱,原来的目标柱变成了缓存柱。这种把一个问题不断拆成更小规模的相同问题就是一种递归的思想,下面看本题代码:
#include <stdio.h>
#include <stdlib.h>
void move(int n,char from,char buffer,char to)//from是出发柱,buffer是缓存柱,to是目标柱
{
if(n==1){
printf("Move disk %d from %c to %c\n",n,from,to);
}
else
{
move(n-1,from,to,buffer);//第一次递归原来的目标柱变成了缓存柱,缓存柱变成了目标柱
printf("Move disk %d from %c to %c\n",n,from,to);//输出一下当前怎么动
move(n-1,buffer,from,to);//和上面同理
}
}
int main()
{
int n;
scanf("%d",&n);
move(n,'A','B','C');
return 0;
}
4-5青蛙过河
书上很详细~
#include <stdio.h>
#include <stdlib.h>
int jump(int s,int y)
{
int k;
if(s==0)
k=y+1;
else
k=2*jump(s-1,y);
return k;
}
int main()
{
int s,y;
while(~scanf("%d %d",&s,&y))
{
printf("%d\n",jump(s,y));
}
return 0;
}
4-6数据结构实验之排序八:快速排序
要不是考试不能用STL
#include <stdio.h>
#include <stdlib.h>
int a[100010];
void sort(int l,int r)
{
int x=a[l],i=l,j=r;
if(l>=r) return;
while(i<j)
{
while(a[j]>=x&&i<j) j--;
a[i]=a[j];
while(a[i]<=x&&i<j) i++;
a[j]=a[i];
}
a[i]=x;
sort(l,i-1);
sort(i+1,r);
}
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(0,n-1);
for(int i=0;i<n;i++)
{
if(i==n-1) printf("%d\n",a[i]);
else printf("%d ",a[i]);
}
}
return 0;
}
4-7第X大的数
就是每次只进一半的快排
#include <stdio.h>
#include <stdlib.h>
int a[100010];
int find(int l,int r,int k)
{
int x=a[l],i=l,j=r;
while(i<j)
{
while(a[j]<=x&&i<j) j--;
a[i]=a[j];
while(a[i]>=x&&i<j) i++;
a[j]=a[i];
}
a[i]=x;
if(i==k) return a[i];
if(i>k)
find(l,i-1,k);
else
find(i+1,r,k);
}
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
int m;
scanf("%d",&m);
while(m--)
{
int k;
scanf("%d",&k);
printf("%d\n",find(0,n-1,k-1));
}
}
return 0;
}
4-8 M–二分查找
#include <stdio.h>
#include <stdlib.h>
int a[3000010];
int find(int l,int r,int k)
{
while(l<=r)
{
int mid=(l+r)/2;
if(a[mid]==k)
return mid;
else if(a[mid]<k)
l=mid+1;
else
r=mid-1;
}
return -1;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
int m;
scanf("%d",&m);
while(m--)
{
int k;
scanf("%d",&k);
printf("%d\n",find(1,n,k));
}
return 0;
}
4-9第k小的数
#include <stdio.h>
#include <stdlib.h>
int a[900010];
int find(int l,int r,int k)
{
int x=a[l],i=l,j=r;
while(i<j)
{
while(a[j]>=x&&i<j)
j--;
a[i]=a[j];
while(a[i]<=x&&i<j)
i++;
a[j]=a[i];
}
a[i]=x;
if(i==k)
return a[i];
if(i>k)
find(l,i-1,k);
else
find(i+1,r,k);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,k;
scanf("%d %d",&n,&k);
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
printf("%d\n",find(0,n-1,k-1));
}
return 0;
}
4-10全排列问题
#include <stdio.h>
#include <stdlib.h>
int a[11];
void swap(int *p,int *q)
{
int t=*p;
*p=*q;
*q=t;
}
//下面两个函数此题没用到,用于有序输出全排列
void cr(int l,int r)
{
if(l>=r) return;
int t=a[r];
for(int i=r;i>l;i--)
{
a[i]=a[i-1];
}
a[l]=t;
}
void cz(int l,int r)
{
if(l>=r) return;
int t=a[l];
for(int i=l;i<r;i++)
{
a[i]=a[i+1];
}
a[r]=t;
}
void prem(int k,int n)
{
if(k==n)
{
for(int i=0;i<=n;i++)
{
if(i==n) printf("%d\n",a[i]);
else printf("%d,",a[i]);
}
}
else
{
for(int i=k;i<=n;i++)
{
swap(&a[k],&a[i]);
prem(k+1,n);
swap(&a[k],&a[i]);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
prem(0,n-1);
}
return 0;
}
小结
递归最重要的就是找规律,考虑问题的时候先从最简单的情况考虑,然后逐渐复杂,寻找复杂问题和简单问题的联系,往往简单问题就是递归边界。