1.迷宫问题
import java.io.*;
public class Main {
static int ysize=30;//y范围
static int xsize=50;//x范围
static char[][]arr=new char[ysize][xsize];//存储迷宫
static boolean[][]help=new boolean[ysize][xsize];//判断此点有没有走过
static BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
static PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
static String len="";//路径
public static void main(String[] args) throws IOException {
for(int i=0;i<ysize;i++){
String s=in.readLine();
arr[i]=s.toCharArray();
}
dfs(0,0);
}
private static void dfs(int y,int x) {
if (!check(y,x)){
return;
}
if(check(y+1,x) && arr[y+1][x]=='0' && help[y+1][x]==false){
len=len+"D";
help[y+1][x]=true;
dfs(y+1,x);
len=len.substring(0,len.length()-1);
}
if(check(y,x-1) && arr[y][x-1]=='0' && help[y][x-1]==false){
len=len+"L";
help[y][x-1]=true;
dfs(y,x-1);
len=len.substring(0,len.length()-1);
}
if(check(y,x+1) && arr[y][x+1]=='0' && help[y][x+1]==false){
len=len+"R";
help[y][x+1]=true;
dfs(y,x+1);
len=len.substring(0,len.length()-1);
}
if(check(y-1,x) && arr[y-1][x]=='0' && help[y-1][x]==false){
len=len+"U";
help[y-1][x]=true;
dfs(y-1,x);
len=len.substring(0,len.length()-1);
}
if (x==49&&y==29){
System.out.println(len);
return;
}
}
static boolean check(int y,int x){//判断此点是否在迷宫里
return y>=0 && y<ysize && x>=0 && x<xsize;
}
}
这道题第一步,把迷宫创建出来。创建一个char二维数组,通过BufferedReader的readLine()和to.CharArray()配合循环将题目里的迷宫放入数组。
第二步,阅读题目可知,限制点移动的条件有:下个点是否走过,是不是0,在不在迷宫内。我们相应的创造方法来解决这些问题,1.创造boolean类型的二维数组help白表示对应的位置是否走过,boolean类型数组默认是false所以当走过时help元素变成true。2.创造check方法判断该点是否在迷宫中y>=0 && y<ysize && x>=0 && x<xsize。
第三步控制点移动,创建dfs方法,设置起始点时(0,0),之后就是简单的判断可否行走然后再进行运算。这一步里关键的是4个if按题目里的从小到大排,并在将下一个点的help设置为true后运行dfs();可以使最后的总和最小,并且很连贯简介。设置一个字符串用来添加"D","L","R","U",并在dfs()内的dfs()后面将字符串截取,配合上一段dfs(),模仿了路径走不通然后退回的过程。
最后就是到达终点后输出字符串len
这道题关键就是迷宫和二数组的结合、条件判断怎么写、走错路径返回并选其他路径走的代码怎么写,最重要的是最后一条,现在写完感觉很简单,写的时候很难想到这种方法,现在能写出来也是一种进步。
static int[][]move={{1,0},{0,-1},{0,1},{-1,0}};
static String[]str={"D","L","R","U"};
static String len="";
private static void dsf(int y,int x) {
if (check(y,x)==false){
return;
}
if(y==ysize&&x==xsize){
System.out.println(len);
return;
}
for(int i=0;i<4;i++){
if(check(y+move[i][0],x+move[i][1])&&hlep[y+move[i][0]][x+move[i][1]]==false&&arr[y+move[i][0]][x+move[i][1]]=='0'){
len=len+ str[i];
hlep[y + move[i][0]][x + move[i][1]]=true;
dsf(y+move[i][0],x+move[i][1]);
len=len.substring(0,len.length()-1);
}
}
}
由于dfs()方法中重复的代码太多且格式相同,可以将重复的代码抽出放入循环里,并将不同的变量放到数组里,根据循环次数的不同进行调用。
2.唯一分解定理
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
//在数学中,唯一分解定理也称为算术基本定理,是数论的重要定理之一。
//该定理断言:任何一个大于1的整数n都可以分解成若干个素因数的连乘积
//如果不计各个素因数的顺序,那么这种分解是惟一的。
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
ArrayList<Integer> list=new ArrayList<>();
for(int i=2;i<=n/2;i++){
while (n%i==0) {//如果余0,那就对除剩下的数再取余,解决一个素数可能再n的组数因数里出现多次的问题
if(panduan(i)){
list.add(i);}
n=n/i;
if(pandaun(n)){//快捷,如果除剩下的数也是素数,根据唯一分解定理,n的质因子就是这几个,直接将其啊放入list,输出list后return结束代码
list.add(n);
System.out.println(list);
return;
}
}
}
if(n>1){
list.add(1);
list.add(n);
System.out.println(list);
}
}
public static boolean pandaun(int i){//判断是不是素数
boolean flag=true;
for (int j=2;j<i/j;j++){
if (i%j==0){
flag=false;
}
}
return flag;
}
}
在数学中,唯一分解定理也称为算术基本定理,是数论的重要定理之一。该定理断言:任何一个大于1的整数n都可以分解成若干个素因数的连乘积。如果不计各个素因数的顺序,那么这种分解是惟一的。
根据这个特性,可以与昨天的收获“某数的因数的因数是某数的因数结合”,试想一下,根据唯一分解定理,n是由多个素数相乘得到,这几个素数是一定的,而当n被素数x除后得到的数m肯定能被分解成多个素数相乘,那么可知n的因子的素数因子也是他的素数因子,且这些素数因子是在根号n以前的,除非n本身是质数。所以可以用循环,而循环条件就是从i=2开始从小到大对n取余,并内嵌while循环防止一个素数因子可以出现多次的情况被忽略。
个人理解:简单的来想,n于其因子使用的素因子是同样的,且都在n以内,只用把for循环范围上到根号n(因为大于根号n的素数肯定只有一个再根号n之前的数可以与他相乘等于n,座椅只用添加一个对n/i是否为玉树的判断就行了),并添加while循环用防止一个素数因子可以出现多次的情况被忽略。
3.最大公约数
//最大公约数
Scanner sc=new Scanner(System.in);
int a=sc.nextInt();
int b=sc.nextInt();
int temp=Math.max(a,b);
int count=Math.min(a,b);
int t=1;
while (t!=0){
t=temp%count;
temp=count;
count=t;
}
System.out.println(temp);
运用数学思维,把a和b看成一个长方形的长宽,具体思路难以言喻,跟着代码带入长方形就能感悟到了
4.总结
今天的收获主要在于做迷宫问题时对二维数组的应用更加精巧,以及设计思路的扩展,比如迷宫问题里dfs()方法模仿了路径走不通退回并重新的过程,以及唯一分解定理中对数学思维的扩展,使解决问题使变得更加具体。