<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本次我們介紹搜尋與圖論篇中DFS和BFS,我們會從下面幾個角度來介紹:
首先我們先來介紹一下DFS和BFS:
DFS和BFS的演演算法依據:
我們首先給出DFS的一元問題:
問題解析:
一元問題解析
我們目前採用DFS演演算法運算,我們需要一次得到資料,然後回溯
那麼我們目前的問題就是:
我們給出演演算法程式碼:
import java.util.Scanner; public class Main { public static final int N = 10; // 存放資料 static int n; static int[] arr = new int[N]; static int[] res = new int[N]; // 判斷是否被使用 static boolean[] isUsed = new boolean[N]; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); n = scanner.nextInt(); for (int i = 0; i < n; i++) { arr[i] = i+1; } dfs(0); } public static void dfs(int x){ // 首先判斷是否可以輸出 if (x == n){ for (int i=0;i < n;i++){ System.out.print(res[i]+ " "); } System.out.println(); } // 開始dfs for (int i = 0; i < n; i++) { // 判斷是否被使用,若被使用,則不能使用;若未被使用,使用並進入下一層 if (!isUsed[i]){ // 未被使用,使用並進入下一層 res[x] = arr[i]; isUsed[i] = true; dfs(x+1); // 下面屬於回溯部分,我們需要恢復原樣,這裡的x已經回溯,不需要覆蓋res的值 isUsed[i] = false; } } } }
我們首先給出DFS的二元問題:
問題解析:
原始方法
首先我們採用最基本的思想,我們採用一元思想,針對n*n的棋盤上的每個位置都進行DFS操作,並對其判斷是否滿足條件
在滿足條件的位置上我們放上皇后並記錄數目,如果到最後皇后的數量足夠,那麼我們就將他輸出
升級方法
我們已經知道他們不能放在同一行和同一列,我們直接採用for將一行中的一個位置選出來,然後對每行DFS操作並判斷是否滿足條件
在滿足條件的位置上我們放上皇后並記錄數目,如果到最後皇后的數量足夠,那麼我們就將他輸出
注意點
我們的n-皇后問題還需要保證對角線上不具有相同棋子
我們採用二元函數的函數y=x以及y=n-x來給出對角線的位置
我們給出演演算法程式碼:
/*原始方法*/ import java.util.Scanner; public class dfsDouble { static final int N = 20; // 記錄資料 static int n; static char[][] arr = new char[N][N]; // 記錄行,列,對角線,反對角線 static boolean[] row = new boolean[N]; static boolean[] col = new boolean[N]; static boolean[] dg = new boolean[2*N-1]; static boolean[] udg = new boolean[2*N-1]; // 主函數 public static void main(String[] args) { Scanner scanner = new Scanner(System.in); n = scanner.nextInt(); for (int i = 0;i < n;i++){ for (int j = 0; j < n; j++) { arr[i][j] = '.'; } } dfs(0,0,0); } // DFS private static void dfs(int x,int y,int u) { // y到頭,換行 if(y == n){ y = 0; x++; } // 老規矩判斷輸出條件 if (x == n){ if (u == n){ for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { System.out.print(arr[i][j]); } System.out.println(); } System.out.println(); } return; } // 進行dfs(不選的情況,選該行的其他點位) dfs(x, y + 1, u); // 判斷是否符合條件 if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n]) { arr[x][y] = 'Q'; row[x] = col[y] = dg[x + y] = udg[x - y + n] = true; // 進行dfs(符合條件選,繼續下一步) dfs(x, y + 1, u + 1); row[x] = col[y] = dg[x + y] = udg[x - y + n] = false; arr[x][y] = '.'; } } } /*升級方法*/ import java.util.Scanner; public class dfsDouble { static final int N = 20; // 記錄資料 static int n; static char[][] arr = new char[N][N]; // 記錄列,對角線,反對角線 static boolean[] col = new boolean[N]; static boolean[] dg = new boolean[2*N-1]; static boolean[] udg = new boolean[2*N-1]; // 主函數 public static void main(String[] args) { Scanner scanner = new Scanner(System.in); n = scanner.nextInt(); for (int i = 0;i < n;i++){ for (int j = 0; j < n; j++) { arr[i][j] = '.'; } } dfs(0); } // DFS private static void dfs(int u) { // 我們採用每行取一個的策略,這裡的u就是x if (u == n){ for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { System.out.print(arr[i][j]); } System.out.println(); } System.out.println(); return; } // 我們取滿足條件的位置 for (int j = 0; j < n; j++) { if (!col[j] && !dg[u+j] && !udg[u - j + n]){ arr[u][j] = 'Q'; col[j] = dg[u+j] = udg[u-j+n] = true; dfs(u+1); col[j] = dg[u+j] = udg[u-j+n] = false; arr[u][j] = '.'; } } } }
我們這裡利用DFS來求解一道難題:
我們給出一個簡單範例來表明重心:
我們來簡單介紹一下:
輸入資料
第一個是操作次數,然後後面成對書寫,表示兩者相連
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6
重心介紹
我們上圖中的黑筆書寫部分是由上述資料所搭建出來的無向圖,我們上面用樹的形式寫出
我們的棕筆部分是指去掉該點之後,剩餘的聯通點分塊的個數中的最大塊,我們要測試全部的點位,並給出這些最大塊的最小快
思路分析
首先我們要遍歷所有的點,一一求解該點刪除後的最大塊
我們刪除該點後,其連通區域主要分為兩部分:該點的子點,該點的上一個點的個數去除該點以及該點子類的個數
我們給出相關程式碼:
import java.util.Scanner; public class Main { final static int N = 100010; // 首先我們用單連結串列模擬圖 static int n; static int idx; static int[] h = new int[N]; static int[] e = new int[N*2]; static int[] ne = new int[N*2]; // 判定是否已經經過 static boolean[] isPassed = new boolean[N*2]; // 最大值 static int ans = N; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); n = scanner.nextInt(); // 將頭節點設為-1,方便判斷 for (int i = 1; i < N; i++) { h[i] = -1; } // 進行連線 for (int i = 0; i < n-1; i++) { int a = scanner.nextInt(); int b = scanner.nextInt(); // 注意是無向邊,我們需要雙向連線 add(a,b); add(b,a); } // 開始遍歷 dfsMethod(1); // 最後輸出結果 System.out.println(ans); } // dfs操作 private static int dfsMethod(int u) { // 連通塊的最大值 int res = 0; // 首先將自己設定為已經過點 isPassed[u] = true; // 該點以及子類的點數(目前已包含自己點) int sum = 1; // 開始遍歷子點 for (int i = h[u];i != -1;i = ne[i]){ // 將每個點用變數表示出來 int j = e[i]; // 如果該點沒有經過,對其dfs遍歷 if (!isPassed[j]){ // 遍歷時需要返回sum來獲得下列點的大小,為了得到ans做準備 int s = dfsMethod(j); // 和res比較,獲得連通塊最大值 res = Math.max(res,s); // 將子類點新增到sum中 sum += s; } } // 我們還需要與拋棄該點後上面的點所產生的res作比較 res = Math.max(res,n-sum); // 返回最小的ans ans = Math.min(ans,res); return sum; } // 我們需要一個單連結串列連線的函數 public static void add(int a,int b){ e[idx] = b; ne[idx] = h[a]; h[a] = idx++; } }
我們給出BFS走迷宮題目:
問題解析:
BFS運作
我們給出演演算法程式碼:
import java.util.Scanner; public class bfs { static final int N = 100; // 存放資料,存放是否使用 static int n,m,hh,tt; static int[][] arr = new int[N][N];// 地圖 static int[][] isPassed = new int[N][N];// 是否經過,若經過修改為距離 static PII[] queue = new PII[N*N];// 佇列 public static void main(String[] args) { Scanner scanner = new Scanner(System.in); n = scanner.nextInt(); m = scanner.nextInt(); for (int i=1;i <= n;i++){ for (int j=1;j <= m;j++){ // 輸入0/1 arr[i][j] = scanner.nextInt(); // 全部設定為未pass isPassed[i][j] = -1; } } int res = bfsMethod(); System.out.println(res); } private static int bfsMethod() { // 初始設定 hh = 0 ; tt = -1; //佇列的頭節點=0,尾節點 = 0; isPassed[1][1] = 0; // 我們首先站在的是第一個點,所以值距離設定為0 queue[++tt] = new PII(1,1); //然後將第一個點下標存入q佇列中 // 提前設定好移動方向(分別對應方向) int[] xmove = {-1,0,1,0}; int[] ymove = {0,1,0,-1}; // 遍歷queue while (hh <= tt){ PII t = queue[hh++]; //每一次將頭結點拿出來 for(int i = 0 ; i < 4 ; i ++ ) {//然後進行下一步要往哪裡走,這裡可能有多重選擇可走 int x = t.x + xmove[i]; //這裡進行x軸向量判斷 int y = t.y + ymove[i];//這裡進行y軸向量的判斷 //如果x,y滿足在地圖中不會越界,然後地圖上的點g是0(表示可以走), //然後這裡是沒走過的距離d是-1; if (x > 0 && x <= n && y > 0 && y <= m && arr[x][y] == 0 && isPassed[x][y] == -1) { //將現在可以走的點(x,y)加上上一個點計數距離的點加上一,就是現在走到的點的距離 isPassed[x][y] = isPassed[t.x][t.y] + 1; queue[++tt] = new PII(x, y);//然後將這一個可以走的點存入佇列尾 } } } return isPassed[n][m]; //最後返回的是地圖走到盡頭最後一個位置的位置統計的距離 } //這是一個用來儲存兩個座標的類Pair static class PII{ int x,y; public PII(int x,int y){ this.x = x; this.y = y; } } }
我們給出BFS八數碼題目:
x
恰好不重不漏地分佈在這 3×3的網格中。x
與其上、下、左、右四個方向之一的數位交換(如果存在)。我們需要將八數碼從下列形式變成順序形式:
/*原八數碼*/ 1 2 3 x 4 6 7 5 8 /*完善八數碼*/ 1 2 3 4 5 6 7 8 x /*變化順序*/ 1 2 3 1 2 3 1 2 3 1 2 3 x 4 6 4 x 6 4 5 6 4 5 6 7 5 8 7 5 8 7 x 8 7 8 x
問題解析:
八數碼問題解析
我們這裡要計算最小的移動步數,那麼我們就需要採用BFS來計算最近的
其實和之前的走迷宮非常相似,我們將x與上下左右四個方向的數進行對換,然後比較是否為最終結果即可
我們給出演演算法程式碼:
import java.util.*; public class bfs { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // 開始狀況 String start = ""; for(int i = 0 ; i < 9 ; i ++ ){ String s = scanner.next(); start += s; } // 結束狀況 String end = "12345678x"; // bfs迴圈 System.out.println(bfsMethod(start,end)); } public static int bfsMethod(String start,String end){ // 雜湊表存放字串和對應的移動步數 HashMap<String,Integer> hashMap = new HashMap<String, Integer>(); // 佇列存放字串 Queue<String> queue = new LinkedList<>(); // 存放第一個點(還未開始,啟動步數為0) hashMap.put(start,0); queue.add(start); while (!queue.isEmpty()){ // 將head資料拿出來 String s = queue.poll(); // 首先判斷是否符合條件 if (s.equals(end)) return hashMap.get(s); // 找到x座標 int index = s.indexOf("x"); // 計算對應位置 int x = index/3; int y = index%3; // 然後上下左右移動判斷 int[] xmove = {1,0,-1,0}; int[] ymove = {0,1,0,-1}; for (int i=0;i<4;i++){ int a = x + xmove[i]; int b = y + ymove[i]; //如果這種情況沒有超出邊界 if(a >= 0 && a < 3 && b >= 0 && b < 3){ //將這種情況的字串轉化成字元陣列,能夠有下標進行交換 char[] arr = s.toCharArray(); //然後交換x跟沒有超出邊界的值進行交換,二維轉成一維下標x*3+y; swap(arr, index, a * 3 + b); //然後將字元陣列轉化成字串 String str = new String(arr); //如果這種情況對應的value值是null,說明還沒有走過 if(hashMap.get(str) == null){ //然後將這種情況對應進行上一步的距離加上1 hashMap.put(str,hashMap.get(s) + 1); //然後將新的情況插入到隊尾中 queue.offer(str); } } } } return -1; } // 交換演演算法 public static void swap(char[] arr,int x,int y){ char temp = arr[x]; arr[x] = arr[y]; arr[y] = temp; } }
我們這裡利用BFS來求解一道難題:
我們採用BFS來逐層遞進,其原理其實和前面兩道題相同:
import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; public class bfsssss { final static int N = 100010; // 單連結串列模擬圖 static int n,m; static int hh,tt; static int idx; static int[] h = new int[N]; static int[] e = new int[N]; static int[] ne = new int[N]; // 距離儲存以及佇列 static int[] distance = new int[N]; static int[] queue = new int[N]; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); n = scanner.nextInt(); m = scanner.nextInt(); // 初始化 for (int i = 1; i < N; i++) { h[i] = -1; distance[i] = -1; } // 賦值 for (int i = 0;i < m;i++ ){ int a = scanner.nextInt(); int b = scanner.nextInt(); add(a,b); } // BFS操作 int res = bfsFind(); // 輸出 System.out.println(res); } // bfs操作 public static int bfsFind(){ // 設定hh,tt hh = 0; tt = -1; // 第一個點距離為0 distance[1] = 0; // 將第一個點加入佇列 queue[++tt] = 1; // 開始佇列迴圈 while (hh <= tt){ int t = queue[hh++]; // 取得該點,對其ne進行處理 for (int i = h[t]; i != -1; i = ne[i]) { // 得到該子點,進行處理 int s = e[i]; if (distance[s] == -1){ // 如果沒有經過就設定dis,並且加入佇列 distance[s] = distance[t] + 1; queue[++tt] = s; } } } return distance[n]; } // 經典單連結串列新增方法 public static void add(int a,int b){ e[idx] = b; ne[idx] = h[a]; h[a] = idx; idx++; } }
以上就是Java搜尋與圖論之DFS和BFS演演算法詳解的詳細內容,更多關於Java DFS BFS的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45