递归
例题
递归实现指数型枚举
从 1∼n这 n个整数中随机选取任意多个,输出所有可能的选择方案。
输入格式
输入一个整数 n。
输出格式
每行输出一种方案。
同一行内的数必须升序排列,相邻两个数用恰好 1 个空格隔开。
对于没有选任何数的方案,输出空行。
各行(不同方案)之间的顺序任意。
数据范围
1≤n≤15
输入样例:
3
输出样例:
3 2 2 3 1 1 3 1 2 1 2 3
import java.util.*;
public class Main{
static int N=16;
static int n;
static int []st=new int[N]; //表状态,0表示未考虑,1表示选,2表示不选
static void df(int u){
if(u>n){ //递归出口,输出选择的数
for(int i=1;i<=n;i++){
if(st[i]==1)
System.out.print(i+" ");
}
System.out.println();
return ;
}
//也可不恢复现场
st[u] =2; //未选择,递归第一个选的分支
df(u+1);
st[u] =0; //恢复现场
st[u]=1;//第二个分支,选了
df(u+1);
st[u]=0;//恢复现场
}
public static void main(String[] args){
Scanner scan =new Scanner(System.in);
n=scan.nextInt();
df(1);
scan.close();
}
}
递归实现排列型枚举
把 1∼n 这 n个整数排成一行后随机打乱顺序,输出所有可能的次序。
输入格式
一个整数 n。
输出格式
按照从小到大的顺序输出所有方案,每行 1 个。
首先,同一行相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。
数据范围
1≤n≤9
输入样例:
3
输出样例:
1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1
import java.util.*;
public class Main{
static int N=10;
static int[] st=new int[N]; //存放第u个位置放什么数
static boolean[] use=new boolean[N];//表示是否选用了i
static int n;
public static void dfs(int u){
if(u>n){ //递归出口,表示u个位置都已存放数
for(int i=1;i<=n;i++){
System.out.print(st[i]+" ");
}
System.out.println();
return ;
}
//枚举每个分支
for(int i=1;i<=n;i++){
if(!use[i]){ //如果数i没有用过
st[u]=i; //第u个位置放i
use[i]=true;
dfs(u+1);
//恢复现场
st[u]=0; //第u个位置未选用i
use[i]= false;
}
}
}
public static void main(String[] args){
Scanner scan=new Scanner(System.in);
n=scan.nextInt();
dfs(1);
scan.close();
}
}
时间复杂度:n*(1+n+n(n-1)+......+n!)<n*3n!
递归实现组合型枚举
从 1∼n这 n个整数中随机选出 m个,输出所有可能的选择方案。
输入格式
两个整数 n,m在同一行用空格隔开。
输出格式
按照从小到大的顺序输出所有方案,每行 11 个。
首先,同一行内的数升序排列,相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如
1 3 5 7
排在1 3 6 8
前面)。数据范围
n>0,
0≤m≤n,
n+(n−m)≤25输入样例:
5 3
输出样例:
1 2 3 1 2 4 1 2 5 1 3 4 1 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5
import java.util.*;
public class Main{
static int N=30;
static int n,m;
static int[] st=new int[N]; //存放选择的数
public static void dfs(int u,int k){ //u表示位置。从k开始枚举
if(m>u+n-k) return ; //剪枝优化,当m-u+1>n-k+1时
if(u==m+1){ //递归出口,u个位置都已有数
for(int i=1;i<=m;i++){
System.out.print(st[i]+" ");
}
System.out.println();
return ;
}
for(int i=k;i<=n;i++){ //枚举
st[u]=i; //第u个位置存放i
dfs(u+1,i+1); //递归调用
st[u]=0; //第u个位置不存放i,恢复现场
}
}
public static void main(String[] args){
Scanner scan=new Scanner(System.in);
n=scan.nextInt();
m=scan.nextInt();
dfs(1,1);
scan.close();
}
}
带分数
题目描述:
100 可以表示为带分数的形式:100=3+69258714
还可以表示为:100=82+3546197
注意特征:带分数中,数字 1∼9 分别出现且只出现一次(不包含 0)。
类似这样的带分数,100 有 11 种表示法。输入格式
一个正数
输出格式
输出输入数字用数码 1∼9 不重复不遗漏地组成带分数表示的全部种数。数据范围
1≤N<106
1输出样例
输入样例1:100
1
输出样例1:11
1
输入样例2:105
1
输出样例2:6
费解的开关
你玩过“拉灯”游戏吗?
25盏灯排成一个 5×5的方形。
每一个灯都有一个开关,游戏者可以改变它的状态。
每一步,游戏者可以改变某一个灯的状态。
游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。
我们用数字 1表示一盏开着的灯,用数字 0表示关着的灯。
下面这种状态
10111 01101 10111 10000 11011
在改变了最左上角的灯的状态后将变成:
01111 11101 10111 10000 11011
再改变它正中间的灯后状态将变成:
01111 11001 11001 10100 11011
给定一些游戏的初始状态,编写程序判断游戏者是否可能在 66 步以内使所有的灯都变亮。
输入格式
第一行输入正整数 n,代表数据中共有 n个待解决的游戏初始状态。
以下若干行数据分为 n 组,每组数据有 5行,每行 5 个字符。
每组数据描述了一个游戏的初始状态。
各组数据间用一个空行分隔。
输出格式
一共输出 n 行数据,每行有一个小于等于 6的整数,它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。
对于某一个游戏初始状态,若 6 步以内无法使所有灯变亮,则输出 −1。
数据范围
0<n≤500
输入样例:
3 00111 01011 10001 11010 11100 11101 11101 11110 11111 11111 01111 11111 11111 11111 11111
输出样例:
3 2 -1
思路:
1.第一行的操作确定,则整个操作确定,枚举对第一行共32种操作,对第一行的操作是解题的精髓,
2.对第2,3,4行的操作要根据其前一行的状态进行文章来源:https://www.toymoban.com/news/detail-773982.html
3.检查最后一行是否符合状态文章来源地址https://www.toymoban.com/news/detail-773982.html
import java.util.*;
public class Main{
static int[][] g=new int[5][5];
static int[][] st=new int[5][5];
static int ans=Integer.MAX_VALUE;
static int[] dx= {0,0,1,0,-1},dy= {0,-1,0,1,0}; //原地,左下右上
static void turn(int x,int y) {
for(int i=0;i<5;i++) {
int a=x+dx[i],b=y+dy[i];
if(a>=0&&b>=0&&a<5&&b<5) { //控制边界
st[a][b] ^=1;
}
}
}
static int work() {
//对第一行一共有32次操作
for(int l=0;l<32;l++) {
int step=0;
for(int i=0;i<5;i++) {
st[i]=Arrays.copyOf(g[i], g[i].length);
}
//操作第一行
for(int i=0;i<5;i++) {
if((l >> i&1)==1) { //如果l对应的二进制数为1,表明要对这个灯进行一次按灯操作,否则就是不操作,从而枚举32种情况
turn(0,i);
step++;
}
}
//对2,3,4行进行操作
for(int i=0;i<4;i++) {
for(int j=0;j<5;j++) {
if(st[i][j]==0) {
turn(i+1,j);
step++;
}
}
}
//判断最后一行
boolean succes=true;
for(int i=0;i<5;i++) {
if(st[4][i]==0) { //最后一行若有不亮的,返回false
succes=false;
break;
}
}
if(succes) {
ans=Math.min(ans, step);
}
}
//操作完返回
if(ans<=6) {
return ans;
}else {
return -1;
}
}
public static void main(String[] args){
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
for(int i=0;i<n;i++) {
for(int j=0;j<5;j++) {
String s=scan.next();
for(int k=0;k<5;k++)
g[j][k]=s.charAt(k) - '0';
}
int a=work();
System.out.println(a);
ans=10;
}
scan.close();
}
}
到了这里,关于专题一:递推与递归的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!