package blue_bridge_1;
/*全排列:先找出第一个位置上可以放的数,然后对其余的数进行全排列,知道最后只剩一个数全排列为止。
* 递归思想、深度搜索:
* dfs:
* 1.if 满足结束条件
* return
* 2.深搜:
* for.....
* 判断是否需要交换
* 递归dfs(深度+1)
*/
public class Test {
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//全排列的对象,数组存放
dfs(arr, 0, arr.length - 1);
}
public static void dfs(int[] arr, int start, int end) {//start为当前搜索的深度
// 递归终止条件
if (start == end) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);//输出排列结果
}
System.out.println();
return;
}
for (int i = start; i <= end; i++) {//深搜的范围
//因为每个位置上的值不允许重复,所以需要交换位置
swap(arr, i, start);
dfs(arr, start + 1, end);//递归搜索
swap(arr, i, start);
}
}
//交换
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
具体应用如下:
应用一、(2013蓝桥杯题目----猜灯谜)题目要求:
A 村的元宵节灯会上有一迷题:请猜谜 * 请猜谜 = 请边赏灯边猜
小明想,一定是每个汉字代表一个数字,不同的汉字代表不同的数字。
请你用计算机按小明的思路算一下,然后提交“请猜谜”三个字所代表的整数即可。
请严格按照格式,通过浏览器提交答案。
注意:只提交一个3位的整数,不要写其它附加内容,比如:说明性的文字。
package org.bluebridge.topics;
public class Main {
public static int[] a = {0,1,2,3,4,5,6,7,8,9};
public static void main(String[] args) {
dfs(0);
}
public static void dfs(int m) {
if(m==6) {//一共6个数,符合条件,递归终止,回溯结果
if((100*a[0]+10*a[1]+a[2])*(100*a[0]+10*a[1]+a[2])==(100000*a[0]+10000*a[3]+1000*a[4]+100*a[5]+10*a[3]+a[1]))
System.out.println(100*a[0]+10*a[1]+a[2]);
return;
}
for(int i=m;i<10;i++) {
swap(i,m);
dfs(m+1);
swap(i,m);
}
}
static void swap(int i,int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
应用二、三羊献瑞:
祥瑞生辉+三羊献瑞=三羊生瑞气
相同汉字代表相同的数字,不同汉字代表不同数字,请填写三羊献瑞代表的4位数字(答案唯一),不要填写任何多余内容。
package org.bluebridge.topics;
public class Main {
public static int[] x = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
public static void main(String[] args) {
dfs(0);
}
public static void dfs(int index) {
if (index == 8) {//因为有8个不同的汉字代表8个数,所以当有8个数时不满足递归条件,递归结束
if ((1000 * x[0] + 100 * x[1] + 10 * x[2] + x[3])
+ (1000 * x[4] + 100 * x[5] + 10 * x[6] + x[1]) == (10000 * x[4] + 1000 * x[5] + 100 * x[2]
+ 10 * x[1] + x[7])) {
System.out.println(1000 * x[4] + 100 * x[5] + 10 * x[6] + x[1]);
}
return;
}
//没有8个数时,就递归深度搜索
for (int i = index; i < 10; i++) {
swap(i,index);
dfs(index + 1);
swap(i,index);
}
}
public static void swap(int i, int j){
int t = x[i];
x[i] = x[j];
x[j] = t;
}
}
上述代码由于条件判断没有考虑完全,所以会输出多个结果,最后一个是正确答案。
应用三、(2018蓝桥杯题目----激光样式):
题目要求:
x星球的盛大节日为增加气氛,用30台机光器一字排开,向太空中打出光柱。安装调试的时候才发现,不知什么原因,相邻的两台激光器不能同时打开!国王很想知道,在目前这种bug存在的情况下,一共能打出多少种激光效果?
显然,如果只有3台机器,一共可以成5种样式,即:
全都关上(sorry, 此时无声胜有声,这也算一种)
开一台,共3种
开两台,只1种
30台就不好算了,国王只好请你帮忙了。
要求提交一个整数,表示30台激光器能形成的样式种数。
package org.bluebridge.topics;
public class Main {
public static int res = 0;//满足条件的结果数
public static int[] x = new int[30];//30个灯,0代表关,1代表开
public static void main(String[] args) {
dfs(0);
System.out.println(res);
}
public static void dfs(int index){
if(index == 30){//满足递归条件,共30个灯
res++;
return;
}
if(index == 0 || x[index-1] == 0){
//第一个灯可以取0或1,如果当前灯光的左边没开,则当前灯光可以开业可以关(取0和1)
for(int i=0;i<=1;i++){
x[index] = i;
dfs(index+1);
x[index] = 0;
}
}else{ //如果左边的灯光开了,那当前灯光只能关闭(取0),数组初始化为0
dfs(index+1);
}
}
}
应用四、带分数
问题描述:
100 可以表示为带分数的形式:100 = 3 + 69258 / 714。
还可以表示为:100 = 82 + 3546 / 197。
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。
输入格式:
从标准输入读入一个正整数N (N<1000*1000)
输出格式:
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!
样例输入1
100
样例输出1
11
package blue_bridge_1;
import java.util.Scanner;
public class Test {
public static boolean[] visited = new boolean[10];//1~9这9个数字哪些数字已被使用
public static int[] number = new int[9];//储存1~9这9个数字的排列
public static int ans = 0;//ans为最后输出的种类数
//计算数组number的[left,right]区间所表示的数的值
public static int compute(int left, int right) {
int a = 0;
for (int i = left; i <= right; ++i)
a = a * 10 + number[i];
return a;
}
public static void DFS(int index, int N) {//当前需要排列的是number[index],N为输入的数字
if (index == 9) {找到了1~9这9个数字的一个排列,递归结束
for (int i = 0; i < 7; ++i)//分割带分数的整数部分
for (int j = i + 1; j < 8; ++j) {//分割带分数的分子分母
//计算带分数的整数、分子、分母的值
int x = compute(0, i);
int y = compute(i + 1, j);
int z = compute(j + 1, 8);
if (y % z != 0 || x + y / z != N)//分子不能整除分母或者当前带分数值不等于N
continue;//重新进行循环
++ans;//递增种类数
}
return;//返回上一层
}
for (int i = 1; i < 10; ++i)//遍历1~9这9个数
if (!visited[i]) {//当前遍历到的数还没有使用过
visited[i] = true;//置当前遍历到的数已使用
number[index] = i;//将当前遍历到的数填充到number[index]位置
DFS(index + 1, N);//进行下一层遍历
visited[i] = false;//置当前遍历到的数没使用,遍历下一个数
}
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
DFS(0,input.nextInt());
System.out.println(ans);
}
}