1.dfs(深度优先搜索)
思想:暴力把所有的路径都搜索出来,它运用了回溯,保存这次的位置,深入搜索,都搜索完了便回溯回来,搜下一个位置,直到把所有最深位置都搜一遍,要注意的一点是,搜索的时候有记录走过的位置,标记完后可能要改回来;
回溯法:是一种搜索法,按条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法;
模板
int check(参数)
{
if(满足条件)
return 1;
return 0;
}
void dfs(int step)
{
判断边界
{
相应操作
}
尝试每一种可能
{
满足check条件
标记
继续下一步dfs(step+1)
恢复初始状态(回溯的时候要用到)
}
}
举例(全排列):
import java.util.Scanner;
public class Permutation {
static int n;
static int[] arr; //排列产生的数组
static int[] judge; //标记数字是否已使用
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
arr = new int[n];
judge = new int[n];
dfs(0);
}
public static void dfs(int step){
if(step == n){ //判断边界(n个数排列完毕)
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
System.out.println();
}else{
for (int i = 0; i < n; i++) { //尝试每一种可能(即每次执行到这里所有数都遍历一遍)
if(judge[i]==0){ //满足check条件(即此分支中该数还没使用过)
judge[i]=1; //标记该数在此分支已使用
arr[step] = i+1; //此分支在此次递归中获得的数
dfs(step+1); //继续下一步dfs
judge[i] = 0; //恢复初始状态(回溯的时候要用到)
}
}
}
}
}
2.bfs(宽度/广度优先搜索)
思想:从某点开始,走四面可以走的路,然后在从这些路,在找可以走的路,直到最先找到符合条件的,这个运用需要用到队列(queue),需要稍微掌握这个才能用bfs。
模板
void BFS(){
初始化队列Q;
起点S入队;
标记S已经访问;
while(Q非空){
取Q的队首元素U;
U出队列;
if(u==目标状态){
返回结果;
}
for(所有与U相邻的元素){
if(相邻的元素合法 && 未访问){
入队;
标记访问;
}
}
}
}
如题:
题目(长草)
【问题描述】
小明有一块空地,他将这块空地划分为 n 行 m 列的小块,每行和每列的长度都为 1。
小明选了其中的一些小块空地,种上了草,其他小块仍然保持是空地。
这些草长得很快,每个月,草都会向外长出一些,如果一个小块种了草,则它将向自己的上、下、左、右四小块空地扩展,这四小块空地都将变为有草的小块。
请告诉小明,k 个月后空地上哪些地方有草。
【输入格式】
输入的第一行包含两个整数 n, m。
接下来 n 行,每行包含 m 个字母,表示初始的空地状态,字母之间没有空格。如果为小数点,表示为空地,如果字母为 g,表示种了草。
接下来包含一个整数 k。
【输出格式】
输出 n 行,每行包含 m 个字母,表示 k 个月后空地的状态。如果为小数点,表示为空地,如果字母为 g,表示长了草。
【样例输入】
4 5
.g…
…
…g…
…
2
【样例输出】
gggg.
gggg.
ggggg
.ggg.
【评测用例规模与约定】
对于 30% 的评测用例,2 <= n, m <= 20。
对于 70% 的评测用例,2 <= n, m <= 100。
对于所有评测用例,2 <= n, m <= 1000,1 <= k <= 1000。
考试时我的代码(未使用bfs):
public class Eight {
//最大达到10的9次方,超时
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
String[][] di = new String[n][m];
for (int i = 0; i < n; i++) {
String str = in.next();
for (int j = 0; j < m; j++) {
di[i][j] = String.valueOf(str.charAt(j));
}
}
int k = in.nextInt();
long now = System.currentTimeMillis();
for (int i = 0; i < k; i++) {
di = zhang(di);
}
for (int i = 0; i < di.length; i++) {
for (int j = 0; j < di[0].length; j++) {
System.out.print(di[i][j]);
}
System.out.println();
}
System.err.println(System.currentTimeMillis()-now);
}
public static String[][] zhang(String di[][]) {
String[][] result = new String[di.length][di[0].length];
for (int i = 0; i < result.length; i++) {
for (int j = 0; j < result[0].length; j++) {
if (di[i][j].equals("g")) {
result[i][j] = "g";
} else {
result[i][j] = ".";
}
}
}
for (int i = 0; i < di.length; i++) {
for (int j = 0; j < di[0].length; j++) {
if (di[i][j].equals("g")) {
if (i >= 1) { // 向上长
result[i - 1][j] = "g";
}
if (i <= di.length-2) {
result[i + 1][j] = "g";
}
if (j >= 1) {
result[i][j - 1] = "g";
}
if (j <= di[0].length-2) {
result[i][j + 1] = "g";
}
}
}
}
return result;
}
答案代码(运用了bfs):
// 答案方法,最大10的6次方,不超时
static final int[] dx = {1, 0, -1, 0};
static final int[] dy = {0, 1, 0, -1};
static Scanner sc ;
static int[][] vis = new int[1000][1000];
static int N, M, K;
public static void main(String[] args) throws IOException {
sc = new Scanner(System.in);
N = sc.nextInt();
M = sc.nextInt();
sc.nextLine();
LinkedList<Block> q = new LinkedList<Block>();
for (int i = 0; i < N; i++) {
String line = sc.nextLine();
for (int j = 0; j < M; j++) {
if (line.charAt(j) == 'g') {
q.addLast(new Block(i, j, 0));
vis[i][j] = 1;
}
}
}
K = sc.nextInt();
long now = System.currentTimeMillis();
while (!q.isEmpty()) {
Block b = q.removeFirst();
int month = b.month;
if (month < K) {
for (int i = 0; i <= 3; i++) {
int nx = b.i + dx[i];
int ny = b.j + dy[i];
if (0 <= nx && nx < N && 0 <= ny && ny < M && vis[nx][ny] == 0) {
vis[nx][ny] = 1;
q.addLast(new Block(nx, ny, month + 1));
}
}
}
}
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (vis[i][j] == 1) writer.write('g');
else writer.write('.');
}
writer.write('\n');
}
writer.flush();
System.err.println(System.currentTimeMillis()-now);
}
//草地上的一块
private static class Block {//只能有一个公共类,因此这里使用private或不写
int i;
int j;
int month;
public Block(int i, int j, int month) {//因为类没有参数,所以需要在类中再写一个方法给Block的属性赋值
this.i = i;
this.j = j;
this.month = month;
}
}
3.dfs和bfs的区别
bfs是用来搜索最短径路的解法是比较合适的
比如求最少步数的解,最少交换次数的解,最快走出迷宫等等,因为bfs搜索过程中遇到的第一个解一定是离最初位置最近的,所以遇到第一个解,一定就是最优解,此时搜索算法可以终止
bfs是浪费空间节省时间,dfs是浪费时间节省空间。
因为dfs要走很多的路径,可能都是没用的,(做有些题目的时候要进行剪枝,就是确定不符合条件的就可以结束,以免浪费时间,否则有些题目会TLE);
而bfs可以走的点要存起来,需要队列,因此需要空间来储存,便是浪费了空间,假设有十层,各个结点有2个子节点,那么储存到第10层就要存 2^10-1 个数据,而dfs只需要存10个数据,但是找到答案的速度相对快一点。
特别要注意的一点,dfs不能走T字型,只能走L型