DFS

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);
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值