1. 程式人生 > >關於隊列(還有廣度優先搜索的例題)

關於隊列(還有廣度優先搜索的例題)

男女 void 格子 std 易懂 can pac while names

本博文的目錄:

$1 隊列

$2 隊列的例題

$3 廣度優先搜索的例題

$1 隊列:

  •隊列是什麽?

    隊列是一種特殊的線性表,與棧不同,這種線性表只允許在表的前端(我們稱為front或head)進行刪除操作,在表的後端(我們稱作rear或tail)進行插入操作。所以又叫F(First)I(In)F(First)O(Out)表。(對於棧來說,因為棧只允許在表的後端進行刪除操作,所以叫做L(Last)I(In)F(First)O(Out)表)

  •在隊列裏的元素設定:

 tail / rear:表示隊尾指針,應該指向隊尾元素的所在位置

    head / front :表示隊頭指針,應指向隊頭元素的前一個位置

  •入隊算法:
1     int q[maxn];
2     int head,tail;
3     int n;
4     head=0;//當前隊列的頭指針 
5     tail=1;//當前隊列的為指針 
6     cin>>n;
7     q[tail]=n;//在當前尾指針處存上n的值
8     tail++;//將尾指針加一 

  •出隊算法:
1     int q[maxn];
2     int head=0,tail=5;//假設隊中有5個元素 
3     cout<<q[head++]<<endl;//將隊頭元素輸出

  •循環隊列:

    (1)循環隊列是啥?

      當尾指針指向數組的最後一個元素時,數組將不能再繼續存儲,我們叫做“溢出”。但當隊列的指針指向最後一個元素時,不一定是溢出了,因為對頭指針不一定是0。若隊頭指針不為0,但隊尾指針指向隊列的最後一個元素時,這個隊列理論上是不能繼續存數據的,但是為隊列所開的數組確實有空間,我們稱之為“假溢出”。如果不對隊列進行循環處理,就會造成對空間的極大浪費。這個時候,我們可以將整個隊列看成是一個環,環上的元素就是隊列的元素,隊列的第maxn項後面為隊列的第1項,這樣就可以進行循環數組的使用啦!

    (2)代碼實現:

      光說概念大家肯定不會完全理解,接下來是代碼實現:

1     int q[maxn];
2     int tail,head;
3     int n;
4     cin>>n;
5     q[tail%maxn]=n;//maxn表示q數組(隊列)的長度 
6     tail=(tail+1)%maxn;

      (這只是一個模板,具體的使用方法視情況而定);

$2 隊列的例題

  •例--周末舞會:

【題目描述】

假設在周末舞會上,男士們和女士們進入舞廳時,各自排成一隊。跳舞開始時,依次從男隊和女隊的隊頭上各出一人配成舞伴。規定每個舞曲能有一對跳舞者。若兩隊初始人數不相同,則較長的那一隊中未配對者等待下一輪舞曲。現要求寫一個程序,模擬上述舞伴配對問題。

【輸入】

第一行兩隊的人數;

第二行舞曲的數目。

【輸出】

配對情況。

【輸入樣例】

4 6
7

【輸出樣例】

  1 1

  2 2

  3 3

  4 4

  1 5

  2 6

  3 1

  直接上代碼:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #define maxn 1000010
 5 using namespace std;
 6 int head,tailw,tailm;//將兩個隊列看成一個,頭指針是一樣的,而尾指針則根據男女的人數決定;
 7 int man[maxn],woman[maxn];//將所有男人的編號和所有女人的編號分別存到man和woman隊列裏;
 8 int men,women,m;//men、women代表男人和女人的總數量;
 9 int main(){
10     scanf("%d%d",&men,&women);
11     scanf("%d",&m);
12     for(int i = 0;i < men;++i){
13         man[i] = i+1; //讀入男人的編號;
14     }
15     for(int i = 0;i < women;++i){
16         woman[i] = i+1;//讀入女人的編號;
17     }
18     head = 0;
19     tailw = women; tailm = men;
20     while(head < m){
21         printf("%d %d\n",man[head],woman[head]);
22         man[tailm++] = man[head]; woman[tailw++] = woman[head];
23         head++;
24     }    
25     return 0;
26 }//簡單易懂qaq

$3 廣度優先搜索的例題

  •例--連通塊:

【題目描述】

一個n * m的方格圖,一些格子被塗成了黑色,在方格圖中被標為1,白色格子標為0。問有多少個四連通的黑色格子連通塊。四連通的黑色格子連通塊指的是一片由黑色格子組成的區域,其中的每個黑色格子能通過四連通的走法(上下左右),只走黑色格子,到達該聯通塊中的其它黑色格子。

【輸入】

第一行兩個整數n,m(1≤n,m≤100),表示一個n * m的方格圖。

接下來n行,每行m個整數,分別為0或1,表示這個格子是黑色還是白色。

【輸出】

一行一個整數ans,表示圖中有ans個黑色格子連通塊。

【輸入樣例】

3 3
1 1 1
0 1 0
1 0 1

【輸出樣例】

 3

  

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #define maxn 110
 5 using namespace std;
 6 const int flag[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};//設了一個數組,表示在(i,j)的情況下向4個方向搜索
 7 int a[maxn][maxn],queue[maxn * maxn][2];//queue中存的是搜索到的聯通塊的橫縱坐標
 8 int n,m,ans;
 9 bool p[maxn][maxn];
10 
11 void bfs(int x,int y){
12     int head = 0, tail = 2;
13     queue[1][0] = x,queue[1][1] = y;
14     while(head < tail - 1){
15         ++head;
16         x = queue[head][0];
17         y = queue[head][1];
18         for(int i = 0;i < 4;++i){
19             int x1 = x + flag[i][0];
20             int y1 = y + flag[i][1];
21             if(x1 < 1 || y1 < 1 || x1 > n || y1 > m || !a[x1][y1] || p[x1][y1]) continue;
22             p[x1][y1] = true;
23             queue[tail][0] = x1;
24             queue[tail++][1] = y1;
25         }
26     }
27 }
28 
29 int main(){
30     cin>>n>>m;
31     for(int i = 1;i <= n;++i)
32         for(int j = 1;j <= m ;++j)  cin>>a[i][j];
33     for(int i = 1;i <= n;++i)
34         for(int j = 1;j <= m ;++j)
35             if(a[i][j] && !p[i][j]){
36                 ++ans;bfs(i,j);
37             }
38     cout<<ans<<endl;
39     return 0;
40 }
//本題的思路:搜索為1的元素-->如果為1,將聯通塊的附近搜索-->將搜過的元素標為0-->搞定!

關於隊列(還有廣度優先搜索的例題)