⭐️前言⭐️
本篇文章针对《备战蓝桥》的另一个题型展开讲解,递推,其实也就是利用循环来完成递归的效果,递归是大化小,而递推就是计算出每个小的,最后去算出大的,下边我们就来针对几道典型例题来一起感受递推。
🍉博客主页: 🍁【如风暖阳】🍁
🍉精品Java专栏【Javase】、【Java数据结构】、【备战蓝桥】
🍉欢迎点赞 👍 收藏 ⭐留言评论 📝私信必回哟😁🍉本文由 【如风暖阳】 原创,首发于 CSDN🙉
🍉博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言
🍉博客中涉及源码及博主日常练习代码均已上传码云(gitee)
📍内容导读📍
🍅1.简单斐波那契
原题链接
💡 题解思路:
因为斐波那契数列从第三项开始,每一项都是前两项的和,所以利用循环,并设置变量后移,得出后边的项并打印。
🔑代码实现:
import java.util.*;
public class Main {
public static void main(String[]args) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
int a=0,b=1;
for(int i=1;i<=n;i++) {
System.out.print(a+" ");
int c=a+b;
a=b;
b=c;
}
}
}
🍅2.开关问题总结
下边这些题目都属于开关问题模型,它们都有以下特性:
- 每个灯泡只能按一次
- 每个灯泡最后的状态是由能影响其状态的灯泡被按次数的奇偶性决定的,所以顺序无关紧要
🍅2.1费解的开关
原题链接
💡 题解思路:
这道题我们也是通过枚举所有按法,然后找出步数最少的按法,得出最后结果。
题目分析:
1.灯的暗亮情况只与其上下左右的灯被按的次数的奇偶性决定,与
因为要求步数最少,所以一个灯最多只按一次,按两次相当于没按。
2.通过循环枚举第一行所有按与不按的情况,所以按完以后如果第一行的灯灭着,只能通过这个位置的下一行的灯使其变亮(本行因为枚举过所有情况了,所以本行不能再按)。
3.由2.得从第二行开始,每行按与不按的情况都由上一行来决定。
4.当按完最后一行的灯以后(其实已经保证了前四行的灯全亮着),如果第五行还有灯未亮,则无法完成任务。
细节处理:
1.第一行每个灯按与不按的情况共2^5-1种,可以通过二进制数字来表示每个位置的灯的亮与否。
2.按下开关后,所按灯位置的上下左右都需要改变,可以设置偏移量数组完成相应位置的异或1操作,就可以把0变为1,1变成0。
🔑代码实现:
import java.util.*;
public class Main {
final static int N=5;
static int[][]g=new int[N][N];
static int[][]backup=new int[N][N];
static int[]dx={0,0,0,1,-1};
static int[]dy={0,1,-1,0,0};
public static void turn(int x,int y) {
for (int i = 0; i < 5; i++) {
int a=x+dx[i];
int b=y+dy[i];
if(a<0||a>4||b<0||b>4)continue;
g[a][b]^=1;
//异或1完成1变0,0变1的操作
}
}
public static int end() {
int r=Integer.MAX_VALUE;
for (int op = 0; op < 32; op++) {
int step=0;
for (int i = 0; i < 5; i++) {
//右移k位与1判断是否是1
if((op>>i&1)==1) {
step++;
turn(0,i);
}
}//到此处完成对第一行的操作
//本行灯的暗亮状态决定下一行灯的操作
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 5; j++) {
if(g[i][j]==0) {
step++;
turn(i+1,j);
//按该位置的下一行的灯
}
}
}
//完成对最后一行灯的判断
boolean dark=true;
for (int i = 0; i < 5; i++) {
if(g[4][i]==0) {
dark=false;
break;
}
}
if(dark)
r=Math.min(r,step);//记录最小步数
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
g[i][j]=backup[i][j];
}
}
}
if(r>6)return -1;
return r;
}
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
//n组测试数据
while (n-->0) {
//每行输入一个字符串,通过charAt()操作,完成对二维数组的填充
for (int i = 0; i < 5; i++) {
String s=scanner.next();
for (int j = 0; j < 5; j++) {
g[i][j]=s.charAt(j)-'0';
}
}
/*数组拷贝,因为接下来会枚举所有情况并在棋盘上进行改动,
为了保证每种情况的初始状态都是一样的,所以需要提前备份数组*/
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
backup[i][j]=g[i][j];
}
}
System.out.println(end());
}
}
}
🍅2.2翻硬币
原题链接
💡 题解思路:
这道题其实是上边第二题费解的开关的一道简单版,我们可以将其想为灯泡,设置n-1个开关,每个开关控制两个灯的亮暗。
从第一个开始比较,不同就按开关,遍历整个数组,因为在同一个位置按两次相当于没有按,所以题解唯一。
代码实现:
import java.util.*;
public class Main {
final static int N=110;
static char[]start=new char[N];
static char[]end=new char[N];
public static void turn(int i) {
if(start[i]=='*')
start[i]='o';
else
start[i]='*';
}
public static void main(String[]args) {
Scanner sca=new Scanner(System.in);
start=sca.next().toCharArray();
end=sca.next().toCharArray();
int a=0;
for(int i=0;i<start.length-1;i++) {
//因为题目规定一定有解,所以在遍历到倒数第二个硬币的时候,
//完成最后一步操作,最后一个硬币一定状态相同。
if(start[i]!=end[i]) {
turn(i);
turn(i+1);
a++;
}
}
System.out.println(a);
}
}
🍅2.3飞行员兄弟
原题链接
💡 题解思路:
将开关转换为灯泡亮暗问题,最后让开关(灯泡)全处于打开状态即可。
这道题我们乍一看和2.1很像,但我们仔细观察题目可以发现,如果我们用和2.1相同的方法来做,我们会发现不能完成该题,因为2.1我们在对第一行操作进行枚举后,影响第一行灯暗亮状态的只有第二行灯,也就是后边的操作是唯一的,而这道题则不同,影响到一个灯的暗亮状态的有它同行同列的所有灯,所以不能通过相同的方法来解决该题。
但我们可以发现,这道题一共就16个灯泡,我们可以暴力枚举每个灯泡的暗亮状态共2^6种,然后对每种状态进行判断即可。
题解步骤:
1.枚举所有方案
2.按照该方案对灯泡进行操作
3.判断是否全亮,如果全亮记录方案
细节:
1.步数最小:
完成操作后进行判断,如果全亮则比较步数多少,完成实时替换即可.
2.字典序:
在枚举时通过从小到大枚举即可按字典序输出。
3.题解步骤中第二步的操作:
将 i j 利用4*i+j转换为对应数字,使得所枚举出的方案能右移n位进行操作。
代码实现:
import java.util.*;
import java.io.*;
public class Main {
static final int N=4;
static char[][]g=new char[N][N];
static char[][]backup=new char[N][N];
static List<PII>res=new ArrayList<PII>();
static BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
public static int get(int x,int y) {
return 4*x+y;
}
public static void turn_one(int x,int y) {
if(g[x][y]=='+')
g[x][y]='-';
else g[x][y]='+';
}
public static void turn_all(int x,int y) {
for (int i = 0; i < 4; i++) {
turn_one(x,i);
turn_one(i,y);
}
turn_one(x,y);
}
public static void main(String[] args) throws IOException {
for (int i = 0; i < 4; i++) {
g[i]=in.readLine().toCharArray();
}
for (int i = 0; i < 4; i++) {
backup[i]=g[i].clone();
}
for (int op = 0; op < 1<<16; op++) {
List temp=new ArrayList<PII>();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if((op>>get(i,j)&1)==1) {
turn_all(i,j);
temp.add(new PII(i,j));
}
}
}
boolean dark=true;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if(g[i][j]=='+') {
dark=false;
break;
}
}
}
if(dark) {
if(res.isEmpty()||res.size()>temp.size())
res=temp;
}
for (int i = 0; i < 4; i++) {
g[i]=backup[i].clone();
}
}
System.out.println(res.size());
for (PII p:res) {
System.out.println((p.x+1)+" "+(p.y+1));
}
in.close();
}
}
class PII {
int x;
int y;
public PII(int x,int y) {
this.x=x;
this.y=y;
}
}
⚡️最后的话⚡️
总结不易,希望uu们不要吝啬你们的👍哟(^U^)ノ~YO!!如有问题,欢迎评论区批评指正😁