0
点赞
收藏
分享

微信扫一扫

【蓝桥杯】(一)递归与递推 [暴力] [8道题解]

潇湘落木life 2022-03-30 阅读 77

目录


在这里插入图片描述

在这里插入图片描述在这里插入图片描述
记住一些常见的数
在这里插入图片描述

🌟1、简单斐波那契【入门题】

Acwing.717.简单斐波那契


以下数列 `0 1 1 2 3 5 8 13 21 ...`被称为斐波纳契数列。

这个数列从第` 3 `项开始,每一项都等于前两项之和。

输入一个整数` N`,请你输出这个序列的前` N` 项。

输入格式
一个整数 N。

输出格式
在一行中输出斐波那契数列的前 N 项,数字之间用空格隔开。

数据范围

0<N<46

输入样例:

5
1
输出样例:

0 1 1 2 3

思路一 【递归】

在这里插入图片描述

#include <iostream>
using namespace std;
int dfs(int u) { //从下标为0 开始
    if(u == 0) { //第0项
        return 0;
    }
    if (u == 1 || u == 2) { //第1、2项
        return 1;
    }
    if (u > 2) {//第二项之后的
        return dfs(u - 1) + dfs(u - 2);
    }
}
int main () {
    int n;
    cin >> n;
    for (int i = 0; i < n; i ++) {
        cout << dfs(i) << ' ';
    }
    return 0;
}

思路二 【递推】

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    int n;
    cin >> n;
    /*普通变量写法,节省空间*/
    int a = 0, b = 1;
    for (int i = 1; i <= n; i++) {
        cout << a << ' ';
        int c = a + b;
        a = b;
        b = c;
    }
    /*数组递推
    ll f[46];
    f[1] = 0, f[2] = 1;
    for (int i = 3; i <= n; i++) {
        f[i] = f[i - 1] + f[i - 2];
    }
    for (int i = 1; i <= n; i++) {
        cout << f[i] << ' ';
    }
    */
    return 0;
}

🌟2、Acwing92.递归实现指数型枚举

题目描述

题目链接
在这里插入图片描述

思路

AC代码

#include <iostream>
using namespace std;
int dfs(int u) { //从下标为0 开始
    if(u == 0) { //第0项
        return 0;
    }
    if (u == 1 || u == 2) { //第1、2项
        return 1;
    }
    if (u > 2) {//第二项之后的
        return dfs(u - 1) + dfs(u - 2);
    }
}
int main () {
    int n;
    cin >> n;
    for (int i = 0; i < n; i ++) {
        cout << dfs(i) << ' ';
    }
    return 0;
}

🌟3、Acwing .93. 递归实现组合型枚举

题目链接
在这里插入图片描述

思路

在这里插入图片描述

AC代码

#include <bits/stdc++.h>
using namespace std;
const int N = 30;
int path[N];
int n, m;

void dfs (int u, int start ) {
    if (u > m) {
        for (int i = 1; i <= m; i ++ ) {
            cout << path[i] << ' ';
        }
        puts("");
    }
    else {
        for (int i = start; i <= n; i ++) {
            path[u] = i;
            dfs(u + 1, i + 1);
            path[u] = 0;//恢复现场
        }
    }
} 

int main () {
    cin >> n >> m;
    dfs(1,1); //第一层开始  且从1开始枚举
    return 0;
}

🌟4、94. 递归实现排列型枚举

题目链接
在这里插入图片描述

思路

AC代码

#include <bits/stdc++.h>
using namespace std;
const int N = 10;
int path[N];
int st[N];
int n ;
void dfs (int u) {
  if(u > n) {
    for (int i = 1; i <= n; i ++ ) {
      cout << path[i] << ' ';
    }
    cout << endl;
    return;
  }
  for (int i = 1; i <=n ; i ++ ) { //遍历每一个值
    if (!st[i]){
          st[i] = 1;
          path[u] = i;
          dfs (u + 1);
          st[i] = 0; //恢复现场
    }
  }
}
int main () {
  cin >> n;
  dfs(1);
  return 0;
}

🌟5、Awing95. 费解的开关

题目太长了 点链接看
在这里插入图片描述

思路 【类似八数码】

  • 位运算(开关 ^1即可) + 递推
  • 每一个位置最多只会操作一次。操作两次==不操作,自然就不可能是最优解。
  • 递推的时候:第一行是不可以按的,第一行的要按的格子,确定了第二行要按的相应位置。换句话说,只能从下一行去改变上一行的灯的状态。
  • 最后一行是不能按的。【因为它的上面行已经全是1了,我们就无法修改最后一行了】

AC代码

#include <bits/stdc++.h>
using namespace std ;
const int N = 7;
char g[N][N];
int m;//取无穷 并不影响最大值

void open(int x, int y) {
    int dx[5] = {0, -1, 0, 1, 0}, dy[5] = {0, 0, 1, 0, -1};//分别对应 本位 右下左上
    for (int i = 0; i < 5; i ++) {
    	int a = x + dx[i], b = y + dy[i];
        if(a>=0 && a<5 && b>=0 && b<5) {//判断是否在5x5内 
            g[a][b] ^= 1;//异或 同 0 异1
        }
    }
}

int work() {
  int ans = 1e8;
	for (int k = 0; k < 32; k ++) {//枚举第一行所以按法
	  int cnt =0; //cnt要写fou里面 教训!!!
		char tmp[10][10];//储存g 
		memcpy(tmp,g,sizeof g);//copy g —> tmp 
		
		for (int j = 0; j < 5; j ++) {  // <<优先级高于 &(只有1&1 == 1) 
			if ((k >> j) & 1) {  //位运算 举例12和2 二进制分别是 
				cnt ++;			//  01100  		和 00010 
				open (0,j);		//按第4、3位     按第2位 
			} 					 
		}
		
		//根据第一行  递推前四行 
		for (int i = 0; i < 4; i ++) {
			for (int j = 0; j < 5; j ++) {
				if(g[i][j] == '0') {
					cnt ++;
					open(i + 1, j);
				} 
			}
		}
		
		//判断第四行死否全为1 
		bool is_successful = true;
		for(int j = 0; j < 5; j ++) {
			if(g[4][j] == '0') {
				is_successful = false;
				break;
			} 
		}
		
		if(is_successful) {
			ans = min(ans,cnt);
		}
		
		memcpy(g,tmp,sizeof g);//恢复原状 
	} 
	
  if(ans > 6) {
    	  ans = -1;
  	}
	return ans; 
}

int main () {
    cin >> m;
    while ( m --) {
        for (int i = 0; i < 5; i ++) {
                cin >> g[i];
        }
        cout << work() << endl;
    }
    return 0;
}

🌟6、带分数

题目链接

思路

AC代码

#include <bits/stdc++.h> 
using namespace std;
int ans = 0;
const int N = 520;
int had_use[N],ever[N];
int n;

bool check(int a,int c){
	int b = n*c - a*c;
	if(!a||!b||!c) return false; //如果有一个数为0 
	memcpy(ever,had_use,sizeof had_use);//用来判断且不会改变原数组的目的
	while (b) {
		int t = b % 10;//取个位 
		b /= 10; //删除 
		if(!t ||ever[t]) return false;
		ever[t] = 1;
	}
	for (int i = 1; i <= 9; i ++) {
		if(!ever[i]) {
		return false;//判断1-9是否都已经用了
		}
	}
	return true;
}

void dfs_c(int x, int a, int c) {//x:已经用了多少个数 
	if (x >= 10) return;	
	if(check(a, c)) ans ++;
	for (int i =1; i <= 9; i ++) {
		if(!had_use[i]) {//如果这个数没有用过 
			had_use[i] = 1;
			dfs_c(x + 1,a,c*10 + i);//递归下一层 
			had_use[i] = 0;//恢复现场(回溯) 
		}	 
	}
}

void dfs_a(int x,int a) {
	if(a>=n) return;  
	if(a) dfs_c(x,a,0);//如果a满足 就枚举C
	
	for (int i = 1;i <= 9; i ++) {
		if (!had_use[i]) {//如果这个数没有被用过
			had_use[i] = 1;
			dfs_a(x + 1, a*10 + i);
			had_use[i] = 0;
		}
	} 
}

int main () {
	cin >> n;
	dfs_a(0,0);
	cout <<ans << endl;
	return 0;
} 

🌟7、116. 飞行员兄弟

题目链接
在这里插入图片描述

思路

AC代码 [DFS]

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII; 
const int N = 5;
char g[N][N];
int path[N][N];
vector<PII>ans, tmp;

void turn (int x, int y) { 
	if(g[x][y]=='+'){
			g[x][y] ='-';
		}
		else {
			g[x][y] = '+';
		}	
	for(int i = 0;i < 4; i ++) {
		if(g[i][y]=='+'){
			g[i][y] ='-';
		}
		else {
			g[i][y] = '+';
		}
	}
	for(int j = 0;j < 4; j ++) {
		if(g[x][j]=='+'){
			g[x][j] ='-';
		}
		else {
			g[x][j] = '+';
		}
	}
} 

void dfs(int x, int y) {
	if(x==3 && y == 4) { //(3,4)是最后一个格子 
		bool success = true;
		for (int i = 0; i < 4; i ++) {
			for (int j = 0; j < 4; j ++) {
				if (g[i][j] == '+') {
					success = false;
					return ;
				}
			} 
		}
	
	//答案为空 or 答案更优 则更新 
	if(success && (ans.empty()|| tmp.size() < ans.size())) {
		ans = tmp;
		}
	return ;
	}
	if(y ==4) {
		x++,y=0;//移动到下一行 
	}
	turn(x,y); 
	tmp.push_back({x,y});
	dfs(x,y+1);//操作
	//恢复现场
	tmp.pop_back(); 
	turn(x,y); 
	dfs(x,y+1);//不操作 
}


int main () {
	for (int i = 0;i < 4; i ++) {
		cin >>g[i]; 
	}
	dfs(0,0);
	cout << ans.size() << endl ;
	for (int i =0; i < ans.size(); i ++ ) {
		cout << ans[i].first + 1 <<' ' << ans[i].second + 1 << endl;
	}
	return 0;
}

🌟8、1208. 翻硬币

题目链接

在这里插入图片描述

举报

相关推荐

0 条评论