9.6-递归(//n!//最大公约数//穷举n位二进制数//四皇后问题//骨牌组合//踩气球)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chengchencheng/article/details/82464705

递归算法:直接或间接调用自身的算法。

递归函数:用函数自身给出定义的函数。

 

递归的优点:算法简洁易于分析理解。

递归的缺点:分支较多的函数时间、空间复杂度太大。

例1:求n!

#include<iostream>
using namespace std;

int f(int n);

int main(){
	int m;
	cin>>m;
	cout<<f(m)<<endl;
	return 0;
}

int f(int n){    //递归部分
    if(n == 1)
		return n;
	else
		return n*f(n-1);
}

例2:求最大公约数(辗转相除法)

#include<iostream>
using namespace std;

int gcd(int a, int b);

int main(){
	int x, y;
	cin>>x>>y;
	cout<<gcd(x, y)<<endl;
	return 0;
}

int gcd(int a, int b){
    if(b == 0)
		return a;
	else
		return gcd(b, a%b);
}

例3:穷举n位二进制数

#include<iostream>
using namespace std;

void dfs(int n);
void output();

int arr[20];
int m;

int main(){
	cin>>m;
	dfs(0);
	return 0;
}

void dfs(int n){
    if(n == m)   //达到要求穷举的位数,输出当前数组中的数据
		output();
	else
		for(arr[n] = 0; arr[n] < 2; arr[n]++){   //依次在数组中储存0或1
		    dfs(n+1);     //递归搜索下一位数字
		}
}

void output(){
    int i;
	for(i = 0; i < m; i++){
	    cout<<arr[i];
	}
	cout<<endl;
}

例4:四皇后问题

      要求每一皇后所在行,列,斜线 y=x, y=-x方向bu'n不能有其他皇后,无输入,输出四个皇后都可放置的可能的排列方式。

#include<iostream>
using namespace std;

void dfs(int n);
void output();
int cannot_do(int row, int col);

int arr[10];

int main(){
	dfs(0);
	for(int i = 0; i < 4; i++){  //数组初始化,以免影响结果 
		arr[i] = 9;
	} 
	return 0;
}

void dfs(int n){
    if(n == 4)   
		output();
	else
		for(arr[n] = 0; arr[n] < 4; arr[n]++){   //遍历四列 
			if(!cannot_do(n, arr[n])){  //若在该列可放下一个皇后,递归搜索下一层 
			    dfs(n+1);
			}     
		}
}

int cannot_do(int row, int col){
    int i;
	for(i = 0; i < row; i++){  //若在之前任一皇后所在列或斜线上,均不可放新皇后 
	    if(arr[i] == col || ((row - i) == (col - arr[i]) || (i - row) == (col - arr[i]) && !(arr[i] == 9)))
			return 1;
	}
	return 0;
}

void output(){  //输出符合条件的放置方法 
    int i;
	for(i = 0; i < 4; i++){
	    cout<<arr[i];
	}
	cout<<endl;
}

例5:骨牌组合

      由0-6组成00,01,.……,06,11,……,16,……,22,……,66,共28个数字组合,分别编号为0,1,2,……,27.将这28块骨牌排列为7*8的矩阵,将矩阵输入。要求输出可能的骨牌组合情况。

#include<iostream>
using namespace std;

void dfs(int n);
void init();
void output();
int cando(int m, int dire);
int find(int a, int b);


int pre_map[10][10];       //原始输入地图
int arr_map[10][10];   //注册地图
bool map_used[60];
bool data_used[30];

int main(){
	init();
	dfs(0);
}

void dfs(int n){
	int x1, y1, x2, y2;
	if(n == 56)
		output();
	else{
		if(!map_used[n]){
            x1 = n/8; y1 = n%8;   //该数在地图中所在行列
            map_used[n] = true;   //第n个数已被匹配
			for(int i = 0; i < 2; i ++){ //0为向右搜索,1为向下搜索
				if(cando(n, i)){//被匹配数未被使用且组合未被注册
					if(i == 0){   //匹配的数在地图中所在行列
					    x2 = x1; y2 = y1+1;    
					}
					else{
					    x2 = x1+1; y2 = y1;
					}
					map_used[x2*8 + y2] = true;   //被第n个数匹配
					int t = find(pre_map[x1][y1], pre_map[x2][y2]);  //找出这对数所在组合编号 
					arr_map[x1][y1] = t;  //在匹配地图上注册
					arr_map[x2][y2] = t;  //在匹配地图上注册
					data_used[t] = true;  //标记组合被使用
					dfs(n+1);
					map_used[x2*8 + y2] = false;
					data_used[t] = false;
				}
			}
			map_used[n] = false;
		}
		else{
			dfs(n+1);
		}
	}
}

int cando(int m, int dire){
	int x1, x2, y1, y2;
	x1 = m/8; y1 = m%8;
	if((x1 == 6 && dire == 1) || (y1 == 7 && dire ==0))
	    return 0;
	if(dire == 0){
	    x2 = x1; y2 = y1 + 1;
	}
	else{
	    x2 = x1 + 1; y2 = y1;
	}
	if(map_used[x2*8 + y2] == false && data_used[find(pre_map[x1][y1], pre_map[x2][y2])] == false)
		return 1;
	return 0;
}

void init(){
    int i, j;
	for(i = 0; i < 7; i++)
		for(j = 0; j < 8; j++){
		    cin>>pre_map[i][j];
		    arr_map[i][j] = 0;
		}
	for(i = 0; i < 56; i++)
	    map_used[i] = false;
	for(i = 0; i < 28; i++)
		data_used[i] = false;
}

int find(int a, int b){
    int c;
	if(a > b){
		c = a; a = b; b = c;
	}
	if(a == 0)
		return(b);
	else if(a == 1)
		return(b+6);
	else if(a == 2)
		return(b+11);
	else if(a == 3)
		return(b+15);
	else if(a == 4)
		return(b+18);
	else if(a == 5)
		return(b+20);
	else
		return(27);
}

void output(){
	int i, j;
	cout<<endl;
	for(i = 0; i < 7; i++){
		for(j = 0; j < 8; j++){
		    cout<<arr_map[i][j]<<" ";
		}
		cout<<endl;
	}
}

例6.踩气球

描述:六一儿童节,小朋友们做踩气球游戏,气球的编号是1~100,两位小朋友各踩了一些气球,要求他们报出自己所踩气球的编号的乘积。现在需要你编一个程序来判断他们的胜负,判断的规则是这样的:如果两人都说了真话,数字大的人赢;如果两人都说了假话,数字大的人赢;如果报小数字的人说的是真话而报大数字的人说谎,则报小数字的人赢(注意:只要所报的小数字是有可能的,即认为此人说了真话)。

输入:输入为两个数字,0 0表示结束;

输出:输出为获胜的数字。

输入样例:

36 62 49 343 0 0

输出样例:

62 49

#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;

int judge(int t);

int m, n, x, y;
int used[101];

int main(){
	while(cin >> n >> m && n){
	    memset(used, 0, sizeof(used));
		x = judge(m);
		y = judge(n);
		if(x == y){
		    cout << max(m,n) <<endl;
		}
		else{
		    cout << min(m,n) <<endl;
		}
	}
}

int judge(int t){
	if(t == 1) return 1;
	for(int i = 1; i <= 100; i++){
		if(t%i){
		    continue;
		}
		if(used[i]){
		    continue;
		}
		else{
		    used[i] = 1;
			if(judge(t/i)) return 1;
			used[i] = 0;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/chengchencheng/article/details/82464705
今日推荐