蓝桥杯之递归算法基本框架

有一根27厘米的细木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置上各有一只蚂蚁。

木杆很细,只能同时通过一只蚂蚁。

开始时,蚂蚁的头朝左还是朝右是任意的,它们只会朝前走或调头,但不会后退。

当任意两只蚂蚁碰头时,两只蚂蚁会同时调头朝反方向走。假设蚂蚁们每秒钟可以走1厘米的距离。

编写程序,求所有蚂蚁都离开木杆的最小时间和最大时间。

思路:当两只蚂蚁相撞时,可以看成两只蚂蚁都没有掉头而直接向前爬行,最小时间即沿蚂蚁朝向到达杆外面的最短时间,最长时间即沿蚂蚁朝向到达杆外面的最长时间。

代码:

不用代码,直接画图就可以看出来…

—————————————————

蚂蚁感冒

长100厘米的细长直杆子上有n只蚂蚁。它们的头有的朝左,有的朝右。 

每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。

当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。

这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。

请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。

【数据格式】

    第一行输入一个整数n (1 < n < 50), 表示蚂蚁的总数。

    接着的一行是n个用空格分开的整数 Xi (-100 < Xi < 100), Xi的绝对值,表示蚂蚁离开杆子左边端点的距离。正值表示头朝右,负值表示头朝左,数据中不会出现0值,也不会出现两只蚂蚁占用同一位置。其中,第一个数据代表的蚂蚁感冒了。

    要求输出1个整数,表示最后感冒蚂蚁的数目。

例如,输入:

3

5 -2 8

程序应输出:

1

再例如,输入:

5

-10 8 -20 12 25

程序应输出:

3

思路:

由于存在感冒的蚂蚁,所以这道题不能使用上面的思路,观察发现,如果感冒的蚂蚁朝右,那么,所有在此蚂蚁后面且朝左的蚂蚁都会被感染,同时,在此蚂蚁左边且朝右的蚂蚁都会被感染,如果第一个感冒的蚂蚁朝左也是一个道理。

代码:

#include<cstdio>

#include<cmath>

int main(){

int n,a,result=0,flag=1;

scanf(“%d”,&n);

while(n–){

		int i;
		scanf("%d",&i);
		if(flag){
			a=i;
			flag=0;
		}
		if(a>0){
			if(i>a&&i<0) result++;
			if(i<a&&i>0) result++;
		}
		if(a<0){
			if(i<a) result++;
			if(i>0&&i<abs(a)) result++;
		} 
	}
	printf("%d",result+1);
} 

—————————————————

搭积木

小明最近喜欢搭数字积木。一共有10块积木,每个积木上有一个数字,0~9。

搭积木规则:

每个积木放到其它两个积木的上面,并且一定比下面的两个积木数字小。

最后搭成4层的金字塔形,必须用完所有的积木。

下面是两种合格的搭法:

   0

  1 2

 3 4 5

6 7 8 9

   0

  3 1

 7 5 2

9 8 6 4    

请你计算这样的搭法一共有多少种?

思路:

代码:

#include<cstdio>

void show (int nums[]){
	printf("   %d\n",nums[0]);
	printf("  %d %d\n",nums[1],nums[2]);
	printf(" %d %d %d\n",nums[3],nums[4],nums[5]);
	printf("%d %d %d %d\n",nums[6],nums[7],nums[8],nums[9]);
	printf("\n"); 
}


int N=0;


void g(int a[],int k,int len){
	if(k==len-1){
		if(a[0]>a[1]||a[0]>a[2]||a[1]>a[3]||a[1]>a[4]||a[2]>a[4]||a[2]>a[5]||a[3]>a[6]||a[3]>a[7]||a[4]>a[7]||a[4]>a[8]||a[5]>a[8]||a[5]>a[9]){
			return;
		}else{
			show(a);
			N++;
			return;
		}
	}	
	
	for(int i=k;i<len;i++){
		int t=a[k];a[k]=a[i];a[i]=t;
		g(a,k+1,len);
		t=a[k];a[k]=a[i];a[i]=t;
	}
}


int main(){
	int nums[10]={0,1,2,3,4,5,6,7,8,9};
	g(nums,0,10);
	printf("%d\n",N);
} 

—————————————————

[3.4 组合问题]

问题: 5个中取3个,几种取法(不许用数学公式)

f(m,n) = f(m-1,n) + f(m-1,n-1) 分为不取和要取

代码:

#include<cstdio>

//组合问题
int g(int m,int n){
	
	if(m==n) return 1;
	if(n==0) return 1;
	
	return g(m-1,n)+g(m-1,n-1);
}


int main(){
	
	printf("%d",g(5,3));
	
}

—————————————————

问题:串=”ABC….” 中取3个,所有取法

问题:”ABCDE” 中取3个,所有取法

代码:

#include<cstdio>

int main(){
	
	for(char i='A';i<='E';i++){
		for(char j=i+1;j<='E';j++){
			for(char k=j+1;k<='E';k++){
				printf("%c%c%c\n",i,j,k);
			}
		}
	}
}

问题:AAABBCCCCDD 中取3个,所有取法

思路:建立数组,存储每个字母出现的次数,然后建立保存结果的数组(和原数组一样大),每次考虑一个数组位置,在这个位置,将该位置出现的次数从0到最大进行遍历,然后进行递归,考虑下个数组位置。

代码:

#include<cstdio>

#define MIN(x,y) x>y?y:x

void myprint(int re[],int len){	
	for(int i=0;i<len;i++){
		for(int j=0;j<re[i];j++){
			printf("%c",i+'A');
		}
	}
	printf("\n");
}


void g(int chars[],int re[],int len,int k,int goal){	
	if(k==len){
		if(goal==0){
			myprint(re,len);
		} 
		return;
	}	
	int min=MIN(chars[k],goal);
	for(int i=0;i<=min;i++){
		re[k]=i;
		g(chars,re,len,k+1,goal-i);	
	}	
	re[k]=0;
}


int main(){
	int chars[4]={3,2,4,2};
	int re[4] = {0};
	g(chars,re,4,0,3); 
	
	
}

—————————————————

代表团出访

X星球要派出一个5人组成的观察团前往W星。

其中:

A国最多可以派出4人。

B国最多可以派出2人。

C国最多可以派出2人。

D国最多可以派出1人。

E国最多可以派出1人。

F国最多可以派出3人。

那么最终派往W星的观察团会有多少种国别的不同组合呢?

思路:同上一题的思路,有重复元素的组合。

代码:

#include<cstdio>

#define MIN(x,y) x>y?y:x
int sum;

void myprint(int re[],int len){	
	for(int i=0;i<len;i++){
		for(int j=0;j<re[i];j++){
			printf("%c",i+'A');
		}
	}
	printf("\n");
}

void g(int chars[],int re[],int len,int k,int goal){	
	if(k==len){
		if(goal==0){
			myprint(re,len);
			sum++;
		} 
		return;
	}	
	int min=MIN(chars[k],goal);
	for(int i=0;i<=min;i++){
		re[k]=i;
		g(chars,re,len,k+1,goal-i);	
	}	
	re[k]=0;
}

int main(){
	int chars[6]={4,2,2,1,1,3};
	int re[6] = {0};
	g(chars,re,6,0,5); 
	printf("%d",sum);
	
}

—————————————————

枚举问题:排列枚举,组合枚举

计数问题:排列计数,组合计数

再加上难度:有重复元素

—————————————————

作业题目

A A 2 2 3 3 4 4, 一共4对扑克牌。请你把它们排成一行。

要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌。

请填写出所有符合要求的排列中,字典序最小的那个。

例如:22AA3344 比 A2A23344 字典序小。当然,它们都不是满足要求的答案。

思路:将字符串以升序排列后调用next_permutation(str,str+len)进行全排列,当第一个符合条件的字符串出现时,结束循环。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

int main(){
	
	char str[]="223344AA";
	int len=strlen(str);
	
	do
	{
		int a = strchr(str,'2')-str;
		int b = strchr(str,'3')-str;
		int c = strchr(str,'4')-str;
		int d = strchr(str,'A')-str;
		
		if(str[d+2]=='A'&&str[c+5]=='4'&&str[b+4]=='3'&&str[a+3]=='2'){
			printf("%s",str);
			break;
		}
		
	}while(next_permutation(str,str+len));
	
	return 0;
}

—————————————————

#include<algorithm>
next_permutation(str,str+len);

    原文作者:递归算法
    原文地址: https://blog.csdn.net/t1506376703/article/details/79990011
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞