[2016/03/09] 关于深搜的题目整理和思路 & 蓝桥杯历年试题 - 大臣的路费/颠倒的价牌
2016-03-09 22:05
232 查看
0 一些废话
说废话已经是我的习惯了。那么关于深搜,老早就想整理了,这毕竟是小白我唯一会的算法嘛。同样,网上基本找不到Java的深搜样本,当然,那是因为算法不需要用java写。不过,作为总结和整理,我还是用java写一份吧=-=不过跟C也没什么区别。
1 经典题目:走迷宫
package Basic; import java.util.Scanner; /**深搜走迷宫算法 * 判断是否能从迷宫的入口到达出口 输入: 先输入两个整数表示迷宫的行数m和列数n, 再输入口和出口的坐标,最后分m行输入迷宫, 其中1表示墙,0表示空格每个数字之间都有空格。 输出: 若能到达,则输出"Yes",否则输出"No",结果占一行。 * 16/02/29 * @author Moplast */ public class Main { //为了方便函数访问它,所以定义为类内全局变量 static int num=0; static int minnum=0; static int Rownum,Colnum; static int Beginrow,Begincol,Endrow,Endcol; static int state; public static void main(String[] args) { Scanner sc=new Scanner(System.in); while(sc.hasNext()){ Rownum=sc.nextInt();//迷宫行数 Colnum=sc.nextInt();//迷宫列数 Beginrow=sc.nextInt();Begincol=sc.nextInt();//起点坐标 Endrow=sc.nextInt();Endcol=sc.nextInt();//终点坐标 state=0;//迷宫走通与否状态 int[][] Arr = new int[Rownum][Colnum];//存储迷宫 //将输入数据读入迷宫数组 for(int i=0;i<Rownum;i++){ for(int j=0;j<Colnum;j++){ Arr[i][j]=sc.nextInt(); } } //开始走迷宫,标记开始走的一步(以及之后走的地方)为1(墙) //即不再回头走(回头走也没有意义的) Arr[Beginrow][Begincol]=1; //在这一步上查找下一个可以前进的地方,即开始归溯 //这里为了不让数组变成全局变量(不太好初始化) //所以把数组作为参数传进去了 search(Beginrow,Begincol,Arr); //一个迷宫搜索路径后的最终状态,起始点接通与否 int step_num=Arr[Endrow][Endcol]-1; /*第一个问题:是否可以走通迷宫?*/ if(state==1){ System.out.println("1: Yes"); }else{ System.out.println("1: No"); } /*第二个问题:共有多少种不重复的走法?*/ if(state==1){ System.out.println("2: "+num); } } } private static void search(int row, int col, int[][] Arr) { //第一步判断,是否当前已经走到终点,如果是,更新走通状态,返回 if(row==Endrow && col==Endcol){ state=1; num++; } //r-new row,c-new col int r,c; Arr[row][col]=1;//对可以走通的点进行标记 //接下来开始上下左右尝试走了 //上 r=row-1;c=col; //如果路可以走通,则继续开始找新路 if(canplace(r,c,Arr)) { Arr[r][c]=num+1; search(r,c,Arr);//深搜定义体现出来了,一条道走到黑就是这样~ } //下 r=row+1;c=col; if(canplace(r,c,Arr)){ Arr[r][c]=num+1; search(r,c, Arr); } //左 r=row;c=col-1; if(canplace(r,c,Arr)){ Arr[r][c]=num+1; search(r,c, Arr); } //右 r=row;c=col+1; if(canplace(r,c,Arr)){ Arr[r][c]=num+1; search(r,c, Arr); } } /*本函数用于判断Arr(r,c)是否可以访问*/ private static boolean canplace(int row, int col, int[][] Arr) { //首先,不能越界,四个条件 if(row>=0 && col >=0 && row<Rownum && col<Colnum){ //其次,该处可以通行 if(Arr[row][col]==0) return true; } return false; } }
废话不多说了,因为我的注释里全是废话。
2 蓝桥杯试题:13种*4扑克牌取13张
package Basic; /** * 深搜:13种扑克牌,每种扑克牌有4张。从中取13张,共有多少种? * 【深搜的基本思路】 * main()函数中:先确定第一步,进行初始化。初始化数组、方向数组(如果有)、起始点位置等。 * 然后进行search() * * search()函数中 * 加上方向增量,形成新的坐标。 * 循环内: * ① 先判断(是否出界,是否已经走过,是否……) * ② 给值 * ③ 走向新的坐标 * ④ 判断是否到了终点 * ⑤ 如果没有,则search下一层 * ⑥ 回溯回来,则回复未走标志(因为如果路能走通,是不会回来的) * @author Android * */ public class DFS { //全局变量 static int[] save=new int[14];//拿的13张牌 static int[] rest=new int[14];//13种牌的对应剩下数量 static int num=0; public static void main(String[] args) { for(int i=1;i<14;i++){ rest[i]=4; } search(1); System.out.println(num); } private static void search(int x) { // TODO Auto-generated method stub for(int i=1;i<=13;i++){ if(check(i, x)){ //①先判断(是否出界,是否已经走过,是否……) save[x]=i; //② 给值 ③ 走向新的坐标 if(x==13) //④ 判断是否到了终点 output(); else{ rest[i]--; search(x+1); //⑤ 如果没有,则search下一层 rest[i]++; //⑥ 回溯回来,则回复未走标志(因为如果路能走通,是不会回来的) save[x]=0; } } } } private static boolean check(int i,int x) { if(rest[i]>0 && i>=save[x-1]) //i>=save[x-1]是必要的剪枝操作,保证后一个数大于等于前一个数 return true; return false; } private static void output() { num++; } }同样,废话一堆堆。
3 环排列:珠串问题
留个白,我还没搞懂。4 蓝桥杯试题:大臣的路费
import java.util.Scanner; public class Main { static int n;//n个城市 static boolean[] flag=new boolean[n+1];//记录城市n是否走过 static int[][] map=new int[n+1][n+1];//记录高速公路 static int beginCity,endCity;//记录开始城市,结束城市 static int kmNum=0;//千米数 static int maxkmNum=0;//最大千米数 public static void main(String[] args) { Scanner sc=new Scanner (System.in); while(sc.hasNext()){ n=sc.nextInt(); //这里如果不重新实例化的话,n默认是0 flag=new boolean[n+1]; map=new int[n+1][n+1]; //注意如果有路的话,要储存双向的路径 for(int i=0;i<n-1;i++){ int p=sc.nextInt(); int q=sc.nextInt(); map[p][q]=sc.nextInt(); map[q][p]=map[p][q]; } //从城市1开始深搜 for(int i=1;i<=n;i++){ beginCity=i; flag[i]=true; search(i); flag[i]=false;//这句比较关键,回溯回来要把记录清除 } //知道最大千米数就好办了,叠加即可 int sum=0; for(int i=11;i<maxkmNum+11;i++){ sum+=i; } System.out.println(sum); } } private static void search(int i) { //这里k还是得从1开始,否则会漏掉一些情况 for(int k=1;k<=n;k++){ //检查是否可走 if(check(i,k)){ //可以走的话,就走出这一步,加上千米数,并标记走过 kmNum+=map[i][k]; flag[k]=true; //深搜下一个城市 search(k); //回溯还原之前的操作 kmNum-=map[i][k]; flag[k]=false; } //如果找不到路,且不是原地打转 else if(!check(i,k) && k==n && i!=beginCity){ //记录结束城市 endCity=i; //记录最大千米数 if(kmNum>maxkmNum) maxkmNum=kmNum; //还原记录 flag[i]=false; //output(); return; } } } private static void output() { // TODO Auto-generated method stub System.out.print("BeginCity:"+beginCity); System.out.print(" EndCity:"+endCity); System.out.println(" km:"+kmNum); } private static boolean check(int i,int j) { //三个条件:1. 不是一个城市到自身; 2.i,j之间有通路; 3. 城市j未走过 if(j!=i && map[i][j]>0 && !flag[j]) return true; return false; } }只能拿到3/4的分数。最后一个测试点超时。
我反思一下程序的问题,就是冗余度太高。在之后的遍历中,有的时候不需要往前遍历,因为之前已经算过了。所以其实应该开辟一个存储空间来存储以前的结果,或者说,在输出结果中,应该是BeginCity<EndCity的组合,而程序等于来回反复做了两遍,不超时才怪。
5 蓝桥杯试题:颠倒的价牌
编程序无能,但是这道题挺有意思,所以就用做趣味数学题的方法暴力地蒙了出来。可用的数是0 1 2 5 6 8 9
而显然有算式
2 _ _
+ 5 5 8
————
= 8 _ _
而二百多和八百多都不超过一千,说明颠倒以后,第一个数(千位)和最后一个数(各位)相差不超过1。这么一想只有以下几种组合:
1> 1和2,产生末位9 即 XX9/XXX9
2> 2和5 产生末位0
3> 6和9 产生末位0
4> 8和6 产生末位2
5> 5和9 产生末位6
把这些末位整理一下,发现二百多的末位肯定是2,而八百多的末位肯定是0。否则不能满足算式。
所以亏两百多的价格肯定是 9XX8,而倒过来的价格是8XX6。好,接下来就凑吧,记得凑出来以后带回八百多的价格的时候也要正确才可以。
答案应该是9088,此时赚800多的应该是X90X,X可以为2/5,也可以为6/9
相关文章推荐
- 51nod1284 2 3 5 7的倍数
- AlphaGo首局战胜李世石
- 21. Merge Two Sorted Lists
- 学习进度条
- 转:String StringBuffer StringBuilder区别
- D9
- android MVP架构
- 古堡算式
- POJ1743 Musical Theme 题解&代码
- iOS 动画Animation-2-2: 动画基础:核心动画
- 关于新浪SaeApp--个人使用感受。
- 关于“连接被重置”(转)
- # java对xml文件的基本操作
- Java系统架构师应该具备的知识点
- MySQL索引操作命令详解
- centos安装nfs服务1
- Javascript之this对象初解
- hdu1318 Palindromes(回文)
- 第39级台阶
- Android的onLayout、layout方法讲解