中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

網(wǎng)站開發(fā)實(shí)用技術(shù) 代碼深圳做seo有哪些公司

網(wǎng)站開發(fā)實(shí)用技術(shù) 代碼,深圳做seo有哪些公司,xd軟件可做網(wǎng)站嗎,提供域名申請(qǐng)的網(wǎng)站報(bào)名明年4月藍(lán)橋杯軟件賽的同學(xué)們,如果你是大一零基礎(chǔ),目前懵懂中,不知該怎么辦,可以看看本博客系列:備賽20周合集 20周的完整安排請(qǐng)點(diǎn)擊:20周計(jì)劃 每周發(fā)1個(gè)博客,共20周。 在QQ群上交流答疑&am…

報(bào)名明年4月藍(lán)橋杯軟件賽的同學(xué)們,如果你是大一零基礎(chǔ),目前懵懂中,不知該怎么辦,可以看看本博客系列:備賽20周合集
20周的完整安排請(qǐng)點(diǎn)擊:20周計(jì)劃
每周發(fā)1個(gè)博客,共20周。
在QQ群上交流答疑:

在這里插入圖片描述

文章目錄

  • 1. BFS簡(jiǎn)介和基本代碼
  • 2. BFS與最短路徑
    • 2.1 計(jì)算最短路的長度
    • 2.2 輸出完整的最短路徑
  • 3. BFS與判重
    • 3.1 C++判重
    • 3.2 Java判重
    • 3.3 Python判重

第14周: ?BFS

1. BFS簡(jiǎn)介和基本代碼

??第12周博客用“一群老鼠走迷宮”做比喻介紹了BFS的原理,類似的比喻還有“多米諾骨牌”、“野火蔓延”。BFS的搜索過程是由近及遠(yuǎn)的,從最近的開始,一層層到達(dá)最遠(yuǎn)處。以下面的二叉樹為例,一層一層地訪問,從A出發(fā),下一步訪問B、C,再下一步訪問D、E、F、G,最后訪問H、I。圓圈旁邊的數(shù)字是訪問順序。
在這里插入圖片描述
??一句話概況BFS的思想:全面擴(kuò)散、逐層遞進(jìn)。
??BFS的逐層訪問過程如何編程實(shí)現(xiàn)?非常簡(jiǎn)單,用隊(duì)列,“BFS = 隊(duì)列”。隊(duì)列的特征是先進(jìn)先出,并且不能插隊(duì)。BFS用隊(duì)列實(shí)現(xiàn):第一層先進(jìn)隊(duì)列,然后第二層進(jìn)隊(duì)列、第三層、…。
??上面圖示的二叉樹用隊(duì)列進(jìn)行BFS操作:根節(jié)點(diǎn)A第1個(gè)進(jìn)隊(duì)列;然后讓A的子節(jié)點(diǎn)B、C進(jìn)隊(duì)列;接下來讓B、C的子節(jié)點(diǎn)D、E、F、G進(jìn)隊(duì)列;最后讓E、G的子節(jié)點(diǎn)H、I進(jìn)隊(duì)列。節(jié)點(diǎn)進(jìn)入隊(duì)列的先后順序是A-BC-DEFG-HI,正好按層次分開了。
??在任何時(shí)刻,隊(duì)列中只有相鄰兩層的點(diǎn)。
??下面的代碼輸出圖示二叉樹的BFS序,用隊(duì)列實(shí)現(xiàn)。隊(duì)列和二叉樹參考第6周隊(duì)列和第7周二叉樹的講解。
C++代碼

#include <bits/stdc++.h>
using namespace std;
const int N=100;                  
char t[N];                             //簡(jiǎn)單地用一個(gè)數(shù)組定義二叉樹
int ls(int p){return p<<1;}            //定位左孩子,也可以寫成 p*2
int rs(int p){return p<<1 | 1;}        //定位右孩子,也可以寫成 p*2+1
void bfs(int root) {queue<int> q;                      //定義隊(duì)列q.push(root);                      //第一個(gè)節(jié)點(diǎn)進(jìn)入隊(duì)列while (!q.empty()) {               //用BFS訪問二叉樹int u = q.front();             //讀隊(duì)頭,并輸出cout << t[u];q.pop();                       //隊(duì)頭處理完了,彈走if (t[ls(u)])  q.push(ls(u));  //左兒子進(jìn)隊(duì)列if (t[rs(u)])  q.push(rs(u));  //右兒子進(jìn)隊(duì)列}
}
int main(){t[1]='A';                                //第1層t[2]='B';           t[3]='C';            //第2層t[4]='D'; t[5]='E'; t[6]='F'; t[7]='G';  //第3層t[10]='H';          t[14]='I'; //第4層bfs(1);               //BFS訪問二叉樹,從根節(jié)點(diǎn)1開始。輸出:ABCDEFGHIcout<<"\n";bfs(3);               //BFS訪問二叉樹的子樹,從子節(jié)點(diǎn)3開始。輸出:CFGIreturn 0;
}

Java代碼

import java.util.*;
public class Main {private static final int N = 100;private static char[] t = new char[N];           //簡(jiǎn)單地用一個(gè)數(shù)組定義二叉樹private static int ls(int p) {return p<<1;}       //定位左孩子,也可以寫成 p*2private static int rs(int p) {return (p<<1) | 1;} //定位右孩子,也可以寫成 p*2+1private static void bfs(int root) {Queue<Integer> queue = new LinkedList<>();    //定義隊(duì)列queue.add(root);                              //第一個(gè)節(jié)點(diǎn)進(jìn)入隊(duì)列while (!queue.isEmpty()) {                    //用BFS訪問二叉樹int u = queue.peek();                     //讀隊(duì)頭,并輸出System.out.print(t[u]);queue.poll();                             //隊(duì)頭處理完了,彈走if (t[ls(u)] != '\0')   queue.add(ls(u));   //左兒子進(jìn)隊(duì)列      if (t[rs(u)] != '\0')   queue.add(rs(u));   //右兒子進(jìn)隊(duì)列     }}public static void main(String[] args) {t[1] = 'A';                                            //第1層t[2] = 'B';   t[3] = 'C';                              //第2層t[4] = 'D';   t[5] = 'E';   t[6] = 'F';  t[7] = 'G';   //第3層t[10] = 'H';  t[14] = 'I';                             //第4層bfs(1);              //BFS訪問二叉樹,從根節(jié)點(diǎn)1開始。輸出:ABCDEFGHISystem.out.println();bfs(3);              //BFS訪問二叉樹的子樹,從子節(jié)點(diǎn)3開始。輸出:CFGI}
}

Python代碼

from collections import deque
N = 100
t = [''] * N                            # 簡(jiǎn)單地用一個(gè)數(shù)組定義二叉樹
def ls(p):  return p << 1               # 定位左孩子,也可以寫成 p*2
def rs(p):  return (p << 1) | 1         # 定位右孩子,也可以寫成 p*2+1
def bfs(root):       q = deque()                         # 定義隊(duì)列q.append(root)                      # 第一個(gè)節(jié)點(diǎn)進(jìn)入隊(duì)列while q:                            # 用BFS訪問二叉樹u = q.popleft()                 # 讀隊(duì)頭,并彈走print(t[u], end='')             # 輸出隊(duì)頭if t[ls(u)]:  q.append(ls(u))   # 左兒子進(jìn)隊(duì)列   if t[rs(u)]:  q.append(rs(u))   # 右兒子進(jìn)隊(duì)列   
t[1] = 'A'                              # 第1層
t[2] = 'B'; t[3] = 'C'                  # 第2層
t[4] = 'D'; t[5] = 'E'; t[6] = 'F'; t[7] = 'G'         # 第3層
t[10] = 'H';t[14] = 'I'                 # 第4層
bfs(1)         # BFS訪問二叉樹,從根節(jié)點(diǎn)1開始。輸出:ABCDEFGHI
print()
bfs(3)         # BFS訪問二叉樹的子樹,從子節(jié)點(diǎn)3開始。輸出:CFGI

2. BFS與最短路徑

??求最短路徑是BFS最常見的應(yīng)用。
??BFS本質(zhì)上就是一個(gè)最短路徑算法,因?yàn)樗蛇M(jìn)及遠(yuǎn)訪問節(jié)點(diǎn),先訪問到的節(jié)點(diǎn),肯定比后訪問到的節(jié)點(diǎn)更近。某個(gè)節(jié)點(diǎn)第一次被訪問到的時(shí)候,必定是從最短路徑走過來的。從起點(diǎn)出發(fā),同一層的節(jié)點(diǎn),到起點(diǎn)的距離都相等。
??不過,BFS求最短路有個(gè)前提:任意兩個(gè)鄰居節(jié)點(diǎn)的邊長都相等,把兩個(gè)鄰居節(jié)點(diǎn)之間的邊長距離稱為“一跳”。只有所有邊長都相等,才能用BFS的逐層遞進(jìn)來求得最短路。兩個(gè)節(jié)點(diǎn)之間的路徑長度,等于這條路徑上的邊長個(gè)數(shù)。在這種場(chǎng)景下,BFS是最優(yōu)的最短路算法,它的計(jì)算復(fù)雜度只有O(n+m),n是節(jié)點(diǎn)數(shù),m是邊數(shù)。如果邊長都不等,就不能用BFS求最短路了,路徑長度也不能簡(jiǎn)單地用邊長個(gè)數(shù)來統(tǒng)計(jì)。
??下圖中,A到B、C、D的最短路長度都是1跳,A到E、F、G、H的最短路都是2跳。

在這里插入圖片描述
??用BFS求最短路路徑的題目一般有兩個(gè)目標(biāo):
??(1)最短路徑的長度。答案唯一,路徑長度就是路徑經(jīng)過的邊長數(shù)量。
??(2)最短路徑具體經(jīng)過哪些節(jié)點(diǎn)。由于最短路徑可能有多條,所以一般不用輸出最短路徑。如果要輸出,一般是輸出字典序最小的那條路徑。例如上圖中,A到F的最短路有兩條:A-B-F、A-C-F,字典序最小的是A-B-F。
??BFS最短路徑的常用的場(chǎng)景是網(wǎng)格圖,下面給出一道例題,用這道例題說明如何計(jì)算最短路、如何輸出路徑。

2.1 計(jì)算最短路的長度

例題:馬的遍歷

??馬走日,從一個(gè)坐標(biāo)點(diǎn)出發(fā),下一步有8種走法。第4、5行用dx[]、dy[]定義下一步的8個(gè)方向。設(shè)左上角的坐標(biāo)是(1,1),右下角坐標(biāo)是(n,m)。
??代碼的主體部分是標(biāo)準(zhǔn)的BFS,讓每個(gè)點(diǎn)進(jìn)出隊(duì)列。注意如何用隊(duì)列處理坐標(biāo)。第24行定義隊(duì)列,隊(duì)列元素是坐標(biāo)struct node。
??用dis[][]記錄最短路徑長度,dis[x][y]是從起點(diǎn)s到(x,y)的最短路徑長度。第35行,每擴(kuò)散一層,路徑長度就加1。
C++代碼:

#include <bits/stdc++.h>
using namespace std;
struct node{int x,y;};                    //定義坐標(biāo)。左上角(1,1),右下角(n,m)
const int dx[8]={2,1,-1,-2,-2,-1, 1, 2};  //8個(gè)方向,按順時(shí)針
const int dy[8]={1,2, 2, 1,-1,-2,-2,-1};
int dis[500][500];                        //dis[x][y]: 起點(diǎn)到(x,y)的最短距離長度
int vis[500][500];                        //vis[x][y]=1: 已算出起點(diǎn)到坐標(biāo)(x,y)的最短路
node pre[500][500];                       //pre[x][y]:坐標(biāo)(x,y)的前驅(qū)點(diǎn)
void print_path(node s, node t){          //打印路徑:從起點(diǎn)s到終點(diǎn)tif(t.x==s.x && t.y==s.y) {           //遞歸到了起點(diǎn)printf("(%d,%d)->",s.x,s.y);      //打印起點(diǎn),返回return;}node p;p.x = pre[t.x][t.y].x;    p.y = pre[t.x][t.y].y;print_path(s,p);                     //先遞歸回到起點(diǎn)printf("(%d,%d)->",t.x,t.y);         //在回溯過程中打印,最后打的是終點(diǎn)
}
int main(){int n,m; node s;   cin>>n>>m>>s.x>>s.y;memset(dis,-1,sizeof(dis));dis[s.x][s.y]=0;                      //起點(diǎn)到自己的距離是0vis[s.x][s.y]=1;queue<node> q;q.push(s);                            //起點(diǎn)進(jìn)隊(duì)while(!q.empty()){node now = q.front();q.pop();                          //取隊(duì)首并出隊(duì)for(int i=0;i<8;i++) {            //下一步可以走8個(gè)方向node next;next.x=now.x+dx[i],next.y=now.y+dy[i];if(next.x<1||next.x>n||next.y<1||next.y>m||vis[next.x][next.y])continue;                   //出界或已經(jīng)走過vis[next.x][next.y]=1;         //標(biāo)記為已找到最短路dis[next.x][next.y]=dis[now.x][now.y]+1;  //計(jì)算最短路長度pre[next.x][next.y] = now;    //記錄點(diǎn)next的前驅(qū)是nowq.push(next);                 //進(jìn)隊(duì)列}}for(int i=1;i<=n;i++) {for(int j=1;j<=m;j++)printf("%-5d",dis[i][j]);printf("\n");}// node test; test.x=3; test.y=3;  //測(cè)試路徑打印,樣例輸入:3 3 1 1,終點(diǎn)(3,3)// print_path(s,test);           //輸出路徑:(1,1)->(3,2)->(1,3)->(2,1)->(3,3)->return 0;
}

2.2 輸出完整的最短路徑

??本題沒有要求打印出具體的路徑,不過為了演示如何打印路徑,代碼中加入了函數(shù)print_path(s,t),打印從起點(diǎn)s到終點(diǎn)t的完整路徑。第47行打印起點(diǎn)s=(1,1),終點(diǎn)t=(3,3)的完整路徑:(1,1)->(3,2)->(1,3)->(2,1)->(3,3)。如下圖虛線箭頭所示。
在這里插入圖片描述
??如何記錄一條路徑?在圖上從一個(gè)起點(diǎn)s出發(fā)做一次BFS,可以求s到其他所有點(diǎn)的最短路。為了記錄路徑,最簡(jiǎn)單的方法是每走到一個(gè)點(diǎn)i,就在i上把從起點(diǎn)s到i經(jīng)過的所有點(diǎn)都記下來。例如上圖,從(1,1)出發(fā),下一步可以走到(3,2),就在(3,2)上記錄”(1,1)->(3,2)”;再走一步可以到(1,3),就在(1,3)上接著記錄“(1,1)->(3,2)->(1,3)”;再走一步到(2,1),就在(2,1)上記錄“(1,1)->(3,2)->(1,3)->(2,1)”。這樣做編程簡(jiǎn)單,但是浪費(fèi)空間,因?yàn)槊總€(gè)點(diǎn)上都要記錄從頭到尾的完整路徑。
??《算法競(jìng)賽》123頁“3.4 BFS與最短路徑”介紹了這兩種路徑記錄方法:簡(jiǎn)單方法、標(biāo)準(zhǔn)方法。
??標(biāo)準(zhǔn)的路徑記錄方法是:只在點(diǎn)i上記錄前驅(qū)點(diǎn),也就是從哪個(gè)點(diǎn)走到i的。例如點(diǎn)(1,3),記錄它的前驅(qū)點(diǎn)是(3,2),(3,2)記錄它的前驅(qū)點(diǎn)是(1,1)。當(dāng)需要輸出起點(diǎn)(1,1)到(1,3)的完整路徑時(shí),只需要從(3,2)倒查回去,就能得到完整路徑了。這樣做非常節(jié)省空間,一個(gè)點(diǎn)上只需要記錄前一個(gè)點(diǎn)就行了。
??為什么不在點(diǎn)i上記錄它的下一個(gè)點(diǎn)?請(qǐng)讀者自己思考。
??代碼第8行用node pre[][]記錄路徑,pre[x][y]記錄了坐標(biāo)(x,y)的前驅(qū)點(diǎn)。按照pre[][]的記錄倒查路徑上每個(gè)點(diǎn)的前一個(gè)點(diǎn),一直查到起點(diǎn),就得到了完整路徑。例如上圖,終點(diǎn)為(3,3),pre[3][3]是它的上一個(gè)點(diǎn)(2,1);(2,1)的pre[2][1]是它的上一個(gè)點(diǎn)(1,3);(1,3)的上一個(gè)點(diǎn)是(3,2);(3,2)的上一個(gè)點(diǎn)是(1,1),回到了起點(diǎn)。
??print_path()打印路徑,它是一個(gè)遞歸函數(shù),從終點(diǎn)開始倒查pre[][],一直遞歸到起點(diǎn),然后再回溯回終點(diǎn)。在回溯的過程中從起點(diǎn)開始打印路徑上的點(diǎn),就得到了從起點(diǎn)到終點(diǎn)的正序路徑。
另外,從起點(diǎn)s到終點(diǎn)t可能有多條最短路徑,上面的代碼只記錄了按順時(shí)針的優(yōu)先順序找到的第一條最短路徑。第4、5行的dx[]、dy[]按順時(shí)針定義了8個(gè)方向,然后在第29行遍歷鄰居時(shí),也是按dx[]、dy[]的順序,那么得到的最短路徑就是按順時(shí)針的。
??Java代碼:

import java.util.*;
class Main {static class Node {              //定義坐標(biāo)。左上角(1,1),右下角(n,m)int x, y;Node(int x, int y) {this.x = x;this.y = y;}}public static void printPath(Node s, Node t, Node[][] pre){ //打印路徑:起點(diǎn)s終點(diǎn)tif (t.x == s.x && t.y == s.y) {                       //遞歸到了起點(diǎn)System.out.print("(" + s.x + "," + s.y + ")->");  //打印起點(diǎn),然會(huì)回溯return;}Node p = pre[t.x][t.y];printPath(s, p, pre);                             //先遞歸回到起點(diǎn)System.out.print("(" + t.x + "," + t.y + ")->");  //回溯打印,最后打的是終點(diǎn)}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();Node s = new Node(scanner.nextInt(), scanner.nextInt());int[][] dis = new int[n+1][m+1];   //dis[x][y]:起點(diǎn)到(x,y)的最短距離長度int[][] vis = new int[n+1][m+1];   //vis[x][y]=1:已算出起點(diǎn)到坐標(biāo)(x,y)的最短路Node[][] pre = new Node[n + 1][m + 1];   //pre[x][y]:坐標(biāo)(x,y)的前驅(qū)點(diǎn)int[] dx = {2, 1, -1, -2, -2, -1, 1, 2}; //8個(gè)方向,按順時(shí)針int[] dy = {1, 2, 2, 1, -1, -2, -2, -1};for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)dis[i][j] = -1;dis[s.x][s.y] = 0;                    //起點(diǎn)到自己的距離是0vis[s.x][s.y] = 1;Queue<Node> queue = new LinkedList<>();queue.add(s);                         //起點(diǎn)進(jìn)隊(duì)while (!queue.isEmpty()) {Node now = queue.poll();          //取隊(duì)首并出隊(duì)for (int i = 0; i < 8; i++) {int nx = now.x + dx[i];int ny = now.y + dy[i];if (nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny] == 1) continue;                  //出界或已經(jīng)走過vis[nx][ny] = 1;               //標(biāo)記為已找到最短路dis[nx][ny] = dis[now.x][now.y] + 1;      //計(jì)算最短路長度pre[nx][ny] = now;             //記錄點(diǎn)next的前驅(qū)是nowqueue.add(new Node(nx, ny));//進(jìn)隊(duì)列}}for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) System.out.printf("%-5d", dis[i][j]);            System.out.println();}// Node test = new Node(3, 3);   //測(cè)試路徑打印,樣例輸入:3 3 1 1,終點(diǎn)(3,3)// printPath(s, test, pre);    //輸出路徑:(1,1)->(3,2)->(1,3)->(2,1)->(3,3)->}
}

??Python代碼

from collections import deque
dx = [2, 1, -1, -2, -2, -1, 1, 2]         #8個(gè)方向,按順時(shí)針
dy = [1, 2, 2, 1, -1, -2, -2, -1]
class Node:                               #定義坐標(biāo)。左上角(1,1),右下角(n,m)def __init__(self, x, y):self.x = xself.y = y
def print_path(s, t, pre):                #打印路徑:從起點(diǎn)s到終點(diǎn)tif t.x == s.x and t.y == s.y:         #遞歸到了起點(diǎn)print(f"({s.x},{s.y})->", end="") #打印起點(diǎn),返回returnp = pre[t.x][t.y] print_path(s, p, pre)                 #先遞歸回到起點(diǎn)print(f"({t.x},{t.y})->", end="")     #在回溯過程中打印,最后打的是終點(diǎn)
def main():n, m,u,v = map(int, input().split())s = Node(u,v)dis = [[-1] * (m+1) for _ in range(n+1)] #dis[x][y]: 起點(diǎn)到(x,y)的最短距離長度vis = [[0] * (m+1) for _ in range(n+1)]  #vis[x][y]=1: 已算出起點(diǎn)到(x,y)的最短路pre = [[None] * (m+1) for _ in range(n+1)]  #pre[x][y]: 坐標(biāo)(x,y)的前驅(qū)點(diǎn)dis[s.x][s.y] = 0                           #起點(diǎn)到自己的距離是0vis[s.x][s.y] = 1q = deque([s])                              #起點(diǎn)進(jìn)隊(duì)while q: now = q.popleft()                       #取隊(duì)首并出隊(duì)for i in range(8):                      #下一步可以走8個(gè)方向nx, ny = now.x + dx[i], now.y + dy[i]if nx<1 or nx>n or ny < 1 or ny > m or vis[nx][ny]:continue                        #出界或已經(jīng)走過vis[nx][ny] = 1                     #標(biāo)記為已找到最短路dis[nx][ny] = dis[now.x][now.y] + 1    #計(jì)算最短路長度pre[nx][ny] = now                      #記錄點(diǎn)(nx,ny)的前驅(qū)是nowq.append(Node(nx, ny))                 #進(jìn)隊(duì)列for i in range(1, n + 1):for j in range(1, m + 1):print(f"{dis[i][j]:-5d}", end="")print()    #test = Node(3, 3)                 #測(cè)試路徑打印,樣例輸入:3 3 1 1,終點(diǎn)(3,3)#print_path(s, test, pre)          #輸出路徑:(1,1)->(3,2)->(1,3)->(2,1)->(3,3)->
if __name__ == "__main__":main()

3. BFS與判重

??BFS的題目往往需要“判重”。BFS的原理是逐層擴(kuò)展,把擴(kuò)展出的下一層點(diǎn)(或稱為狀態(tài))放進(jìn)隊(duì)列中。
??在任意時(shí)刻,隊(duì)列中只包含相鄰兩層的點(diǎn)。只有兩層,看起來似乎不多,但是很多情況下是個(gè)極大的數(shù)字。例如一棵滿二叉樹,第25層的點(diǎn)就有225≈3000萬個(gè),隊(duì)列放不下。
??不過在很多情況下,其實(shí)狀態(tài)的總數(shù)量并不多,在層層擴(kuò)展過程中,很多狀態(tài)是重復(fù)的,沒有必要重新放進(jìn)隊(duì)列。這產(chǎn)生了判重的需求。
??用下面的題目說明判重的原理和編程方法。

例題:九宮重排

??題目求從初態(tài)到終態(tài)的最少步數(shù),是典型的BFS最短路路徑問題。
??讓卡片移動(dòng)到空格比較麻煩,改為讓空格上下左右移動(dòng),就簡(jiǎn)單多了??崭竦拿恳徊揭苿?dòng),可能有2、3、4種新局面,如果按3種算,移動(dòng)到第15步,就有315>1千萬種局面,顯然隊(duì)列放不下。不過,其實(shí)局面總數(shù)僅有9!=362880種,隊(duì)列放得下,只要判重,不讓重復(fù)的局面進(jìn)入隊(duì)列即可。

3.1 C++判重

??判重可以用STL map或set。(1)map判重。map是STL容器,存放鍵值對(duì)。鍵有唯一性,鍵和值有一一對(duì)應(yīng)關(guān)系。由于每個(gè)鍵是獨(dú)一無二的,可以用來判重。map的基本用法見下面的例子。

#include <bits/stdc++.h>
using namespace std;
int main(){map<string,int> mp{{"tom",78},{"john",92},{"rose",83}}; //三個(gè)鍵值對(duì)cout << mp["tom"]<<"\n";                //輸出  78cout << mp.count("tom")<<"\n";          //檢查map中是否有"tom"。輸出  1mp["white"]=100;                        //加入新鍵值對(duì),鍵是"white",值是100cout << mp["white"]<<"\n";              //輸出 100cout << mp.count("sam")<<"\n";          //查不到鍵,輸出 0map<int, int> mp2{{2301,89},{2302,98}}; cout << mp2[2301]<<"\n";                //輸出 89map<int, string> mp3{{301,"dog"},{232,"pig"}};cout << mp3[232]<<"\n";                 //輸出 pigreturn 0;
}

??map容器中提供了count()用于統(tǒng)計(jì)鍵的個(gè)數(shù),有鍵返回1,沒有鍵返回0。count()可以用來判重:若某個(gè)鍵的count()等于1,說明這個(gè)鍵已經(jīng)在map中,不用再放進(jìn)map。
??下面給出本題的C++代碼。第22行判重,判斷局面tmp是否曾經(jīng)處理過,第23行把新局面tmp放進(jìn)map。

#include <bits/stdc++.h>
using namespace std;
int dx[] = {-1, 0, 1,  0};  //上下左右四個(gè)方向
int dy[] = { 0, 1, 0, -1};
map <string,int> mp;
int bfs(string s1,string s2){queue<string>q;q.push(s1);mp[s1]=0;           //mp[s1]=0表示s1到s1的步數(shù)是0。另外:mp.count(s1)=1while(q.size()){string ss = q.front();q.pop();int dist = mp[ss];       //從s1到ss的移動(dòng)步數(shù)if(ss==s2)  return dist; //到達(dá)終點(diǎn),返回步數(shù)int k=ss.find('.');      //句點(diǎn)的位置int x=k/3,y=k%3;         //句點(diǎn)坐標(biāo):第x行、第y列for(int i=0;i<4;i++){int nx=x+dx[i], ny=y+dy[i];  //讓句點(diǎn)上下左右移動(dòng)if(nx<0 || ny<0 || nx>2 || ny>2) continue;  //越界string tmp=ss;swap(tmp[k],tmp[nx*3+ny]);  //移動(dòng)if(mp.count(tmp)==0){       //判重,如果tmp曾經(jīng)處理過,就不再處理mp[tmp] = dist+1; //把tmp放進(jìn)map,并賦值。mp[tmp]等于s1到tmp的步數(shù)q.push(tmp);}}}return -1;                      //沒有找到終態(tài)局面,返回-1
}
int main(){string s1,s2;   cin>>s1>>s2;    //初態(tài)局面s1,終態(tài)局面s2cout<<bfs(s1,s2);return 0;
}

??(2)set判重。set是STL的常用容器,set中的元素是有序的且具有唯一性,利用這個(gè)特性,set常用來判重。set的基本用法見下面的例子。

#include <bits/stdc++.h>
using namespace std;
int main() {set<string>st{"111","222","33"};        // 定義 set,插入初值if(st.count("111")) cout <<1;           //有"111",輸出   1else cout <<-1;cout<<"\n";if(st.count("44")) cout <<4;else cout <<-4;                         //無"44",輸出   -4cout <<"\n";st.insert("44");                        //插入"44"if(st.count("44")) cout <<4;            //有"44",輸出   4return 0;
}

??本題用set判重的代碼:

#include <bits/stdc++.h>
using namespace std;
int dx[] = {-1, 0, 1,  0};    //上下左右四個(gè)方向
int dy[] = { 0, 1, 0, -1};
struct node{node(string ss, int tt){s=ss, t=tt;}string s;     //局面int t;        //到這個(gè)局面的步數(shù)
};
set <string> st;   //用set st判重
int bfs(string s1,string s2){queue<node>q;q.push(node(s1,0));st.insert(s1);while(q.size()){node now = q.front();q.pop();string ss = now.s;int dist = now.t;         //從s1到ss的移動(dòng)步數(shù)if(ss==s2)  return dist;  //到達(dá)終點(diǎn),返回步數(shù)int k=ss.find('.');       //句點(diǎn)的位置int x=k/3,y=k%3;          //句點(diǎn)坐標(biāo):第x行、第y列for(int i=0;i<4;i++){int nx=x+dx[i], ny=y+dy[i];          //讓句點(diǎn)上下左右移動(dòng)if(nx<0 || ny<0 || nx>2 || ny>2) continue;  //越界string tmp=ss;swap(tmp[k],tmp[nx*3+ny]);  //移動(dòng)if(st.count(tmp)==0){       //判重,如果tmp曾經(jīng)處理過,就不再處理st.insert(tmp);q.push(node(tmp,dist+1));}}}return -1;                      //沒有找到終態(tài)局面,返回-1
}
int main(){string s1,s2;   cin>>s1>>s2;    //初態(tài)局面s1,終態(tài)局面s2cout<<bfs(s1,s2);return 0;
}

3.2 Java判重

??(1)用map判重

import java.util.*;
public class Main {static int[] dx = {-1, 0, 1, 0};  // 上下左右四個(gè)方向static int[] dy = {0, 1, 0, -1};static Map<String, Integer> mp;public static int bfs(String s1, String s2) {Queue<String> q = new LinkedList<>();q.add(s1);mp.put(s1, 0);                // 0表示s1到s1的步數(shù)是0while (!q.isEmpty()) {String ss = q.poll();int dist = mp.get(ss);  // 從s1到ss的移動(dòng)步數(shù)if (ss.equals(s2)) return dist;  // 到達(dá)終點(diǎn),返回步數(shù)int k = ss.indexOf('.');  // 句點(diǎn)的位置int x = k / 3, y = k % 3;  // 句點(diǎn)坐標(biāo):第x行、第y列for (int i = 0; i < 4; i++) {int nx = x + dx[i], ny = y + dy[i];  // 讓句點(diǎn)上下左右移動(dòng)if (nx < 0 || ny < 0 || nx > 2 || ny > 2) continue;  // 越界StringBuilder tmp = new StringBuilder(ss);tmp.setCharAt(k, tmp.charAt(nx * 3 + ny));  // 移動(dòng)tmp.setCharAt(nx * 3 + ny, '.');if (!mp.containsKey(tmp.toString())) {//判重,如果tmp處理過,就不再處理mp.put(tmp.toString(), dist + 1); //把tmp放進(jìn)map,并賦值為步數(shù)q.add(tmp.toString());}}}return -1;  // 沒有找到終態(tài)局面,返回-1}public static void main(String[] args) {mp = new HashMap<>();Scanner scanner = new Scanner(System.in);String s1 = scanner.next();String s2 = scanner.next();System.out.println(bfs(s1, s2));}
}

??(2)用set判重

import java.util.*;
public class Main {static int[] dx = {-1, 0, 1, 0};  // 上下左右四個(gè)方向static int[] dy = {0, 1, 0, -1};static Set<String> st;static class Node {String s;  // 局面int t;     // 到這個(gè)局面的步數(shù)public Node(String ss, int tt) {s = ss;t = tt;}}public static int bfs(String s1, String s2) {Queue<Node> q = new LinkedList<>();q.add(new Node(s1, 0));st.add(s1);while (!q.isEmpty()) {Node now = q.poll();String ss = now.s;int dist = now.t;  // 從s1到ss的移動(dòng)步數(shù)if (ss.equals(s2)) return dist;  // 到達(dá)終點(diǎn),返回步數(shù)int k = ss.indexOf('.');  // 句點(diǎn)的位置int x = k / 3, y = k % 3;  // 句點(diǎn)坐標(biāo):第x行、第y列for (int i = 0; i < 4; i++) {int nx = x + dx[i], ny = y + dy[i];  // 讓句點(diǎn)上下左右移動(dòng)if (nx < 0 || ny < 0 || nx > 2 || ny > 2) continue;  // 越界StringBuilder tmp = new StringBuilder(ss);tmp.setCharAt(k, tmp.charAt(nx * 3 + ny));  // 移動(dòng)tmp.setCharAt(nx * 3 + ny, '.');if (!st.contains(tmp.toString())) {//判重,如果tmp處理過,就不再處理st.add(tmp.toString());q.add(new Node(tmp.toString(), dist + 1));}}}return -1;  // 沒有找到終態(tài)局面,返回-1}public static void main(String[] args) {st = new HashSet<>();Scanner scanner = new Scanner(System.in);String s1 = scanner.next();String s2 = scanner.next();System.out.println(bfs(s1, s2));}
}

3.3 Python判重

??(1)用set判重

from collections import deque
dx = [-1, 0, 1, 0]  # 上下左右四個(gè)方向
dy = [0, 1, 0, -1]
class Node:def __init__(self, s, t):self.s = s  # 局面self.t = t  # 到這個(gè)局面的步數(shù)
def bfs(s1, s2):q = deque()q.append(Node(s1, 0))st = set()st.add(s1)while q:now = q.popleft()ss = now.sdist = now.t        # 從s1到ss的移動(dòng)步數(shù)if ss == s2:  return dist  # 到達(dá)終點(diǎn),返回步數(shù)k = ss.index('.')x = k // 3y = k % 3for i in range(4):nx = x + dx[i]ny = y + dy[i]if nx < 0 or ny < 0 or nx > 2 or ny > 2:   continue  # 越界tmp = list(ss)tmp[k], tmp[nx * 3 + ny] = tmp[nx * 3 + ny], tmp[k]  # 移動(dòng)tmp = ''.join(tmp)if tmp not in st:  # 判重,如果tmp曾經(jīng)處理過,就不再處理st.add(tmp)q.append(Node(tmp, dist + 1))return -1  # 沒有找到終態(tài)局面,返回-1
s1 = input()  # 初態(tài)局面s1
s2 = input()  # 終態(tài)局面s2
print(bfs(s1, s2))

??(2)用字典判重

from collections import deque
dx = [-1, 0, 1, 0]          # 上下左右四個(gè)方向
dy = [0, 1, 0, -1]
def bfs(s1, s2):q = deque()q.append(s1)mp = {s1: 0}           # 定義字典。mp[s1]=0表示s1到s1的步數(shù)是0 while q:ss = q.popleft()dist = mp[ss]      # 從s1到ss的移動(dòng)步數(shù)if ss == s2:   return dist    # 到達(dá)終點(diǎn),返回步數(shù)k = ss.find('.')x = k // 3y = k % 3for i in range(4):nx = x + dx[i]ny = y + dy[i]if nx < 0 or ny < 0 or nx > 2 or ny > 2:  continue   # 越界tmp = list(ss)tmp[k], tmp[nx * 3 + ny] = tmp[nx * 3 + ny], tmp[k]  # 移動(dòng)tmp = ''.join(tmp)if tmp not in mp:  # 判重,如果tmp曾經(jīng)處理過,就不再處理mp[tmp] = dist + 1  # 把tmp放進(jìn)map,并賦值。mp[tmp]等于s1到tmp的步數(shù)q.append(tmp)return -1  # 沒有找到終態(tài)局面,返回-1
s1 = input()  # 初態(tài)局面s1
s2 = input()  # 終態(tài)局面s2
print(bfs(s1, s2))

習(xí)題:
洛谷搜索提單:https://www.luogu.com.cn/training/112#problems

http://m.risenshineclean.com/news/58655.html

相關(guān)文章:

  • wordpress站群網(wǎng)絡(luò)推廣是什么
  • 上海做網(wǎng)站的費(fèi)用銷售培訓(xùn)
  • 廣告設(shè)計(jì)需要學(xué)多久蘇州百度 seo
  • 網(wǎng)站開發(fā)月薪多少錢小程序推廣運(yùn)營的公司
  • 蘇州網(wǎng)站運(yùn)營公司淘寶關(guān)鍵詞優(yōu)化怎么弄
  • 做視頻網(wǎng)站對(duì)服務(wù)器要去中央電視臺(tái)一套廣告價(jià)目表
  • 百度蜘蛛如何找網(wǎng)站國內(nèi)設(shè)計(jì)公司前十名
  • 溫州網(wǎng)站設(shè)計(jì)工作室軟件開發(fā)平臺(tái)
  • 網(wǎng)站規(guī)劃總結(jié)武漢本地seo
  • 百度做的網(wǎng)站seo資料網(wǎng)
  • 青島開發(fā)區(qū)網(wǎng)站建設(shè)多少錢百度競(jìng)價(jià)排名的利與弊
  • 臨沂做網(wǎng)站的公司哪里有武漢網(wǎng)絡(luò)推廣網(wǎng)絡(luò)營銷
  • 無需域名網(wǎng)站建設(shè)競(jìng)價(jià)什么意思
  • 優(yōu)質(zhì)的外國網(wǎng)站如何推廣app賺錢
  • 學(xué)做日本菜的網(wǎng)站好泉州搜索推廣
  • 山西焦煤集團(tuán)公司網(wǎng)站山東seo推廣
  • 佛山網(wǎng)站建設(shè)公司哪家便宜分銷渠道
  • 機(jī)電網(wǎng)站模板整站優(yōu)化系統(tǒng)
  • 淮安網(wǎng)站建設(shè)公司產(chǎn)品推廣方法有哪些
  • 億唐網(wǎng)不做網(wǎng)站做品牌考試題中國互聯(lián)網(wǎng)公司排名
  • 哪里有專業(yè)做網(wǎng)站國內(nèi)最新新聞事件今天
  • 大學(xué)生做企業(yè)網(wǎng)站東莞關(guān)鍵詞優(yōu)化平臺(tái)
  • 怎么做博客網(wǎng)站上海網(wǎng)絡(luò)seo
  • 網(wǎng)站如何做微信支付寶支付寶支付近期國家新聞
  • 動(dòng)態(tài)網(wǎng)站作業(yè)建網(wǎng)站不花錢免費(fèi)建站
  • 寶塔面板怎么做網(wǎng)站中國市場(chǎng)營銷網(wǎng)網(wǎng)站
  • 深圳龍華建設(shè)工程交易中心網(wǎng)站本溪seo優(yōu)化
  • 轉(zhuǎn)移網(wǎng)站如何轉(zhuǎn)數(shù)據(jù)庫百度知道答題賺錢
  • 常州企業(yè)網(wǎng)站建設(shè)價(jià)格網(wǎng)站優(yōu)化關(guān)鍵詞排名
  • 政府網(wǎng)站建設(shè)被問責(zé)怎么讓網(wǎng)站快速收錄