数据结构之------深度优先搜索(DFS)

来源:互联网 发布:装修画图软件 编辑:程序博客网 时间:2024/05/02 15:38

深度优先搜索

在编程时经常需要用到搜索,因此掌握搜索算法是很重要的,这里介绍一下深度优先搜索并附上代码样例

1、深度优先搜索思想

     深度优先搜索遍历类似于树的先序遍历。假定给定图G的初态是所有顶点均未被访问过,在G中任选一个顶点i作为遍历的初始点,则深度优先搜索递归调用包含以下操作:
(1)访问搜索到的未被访问的邻接点;
(2)将此顶点的visited数组元素值置1;
(3)搜索该顶点的未被访问的邻接点,若该邻接点存在,则从此邻接点开始进行同样的访问和搜索。 
深度优先搜索DFS可描述为:
(1)访问v0顶点;
(2)置 visited[v0]=1;
(3)搜索v0未被访问的邻接点w,若存在邻接点w,则DFS(w)。

2、 遍历过程:

     DFS 在访问图中某一起始顶点 v 后,由 v 出发,访问它的任一邻接顶点 w1;再从 w1 出发,访问与 w1邻 接但还没有访问过的顶点 w2;然后再从 w2 出发,进行类似的访问,… 如此进行下去,直至到达所有的邻接顶点都被访问过的顶点 u 为止。
     接着,退回一步,退到前一次刚访问过的顶点,看是否还有其它没有被访问的邻接顶点。如果有,则访问此顶点,之后再从此顶点出发,进行与前述类似的访问;如果没有,就再退回一步进行搜索。重复上述过程,直到连通图中所有顶点都被访问过为止。

3、深度优先搜索的示例


图中可能存在回路,且图的任一顶点都可能与其它顶点相通,在访问完某个顶点之后可能会沿着某些边又回到了曾经访问过的顶点。
为了避免重复访问,可设置一个标志顶点是否被访问过的辅助数组 visited [ ],它的初始状态为 0,在图的遍历过程中,一旦某一个顶点 i 被访问,就立即让 visited [i] 为 1,防止它被多次访问。

4、深度优先搜索示意图 


   对上图,深度优先搜索遍历的顺序(之一)为:
   v1 →v2→v4→ v8→ v5→v6→v3→v7。

5、深度优先搜索算法:

[java] view plain copy
  1. DFS(G){  
  2.   for( each vertex u∈V[G] ){  
  3.     color[u]  ← WHITE // “未被搜”  
  4.     parent[u] ← null   //父结点  
  5.   }  
  6.   time ← 0 //用于计时的全局变量  
  7.   for( each vertex u∈V[G] ){  
  8.     if( color[u]==WHITE )  
  9.       dfsVisit(u);  
  10.   }  
  11. }  

[java] view plain copy
  1. dfsVisit(u){  
  2.   color[u] ← GRAY //“正在搜”  
  3.   time ← time+1  
  4.   d[u] ← time    //发现时间  
  5.   for( each v∈Adj[u] ){   
  6.     if( color[v]==WHITE ){  
  7.       parent[v]← u  
  8.       dfsVisit(v);  
  9.     }  
  10.   }  
  11.   color[u] ← BLACK  //“已搜索”  
  12.   f[u] ← time ← time+1 //搜完时间  
  13. }  


6、深度优先搜索算法解题实例

hdu 1016
A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime.
Note: the number of first circle should always be 1.
Input:  n (0 < n < 20).
Output: The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. 

Sample Input: 

Sample Output: 
1 4 3 2 5 6
1 6 5 2 3 4

[java] view plain copy
  1. import java.util.Scanner;  
  2.   
  3. class Main{  
  4.     static int k = 0;  
  5.   
  6.     public static void main(String[] args) {  
  7.         Scanner sc = new Scanner(System.in);  
  8.         while (sc.hasNext()) {  
  9.             int n = sc.nextInt(); // 输入个数  
  10.             int[] a = new int[n]; // 用来装(1~n)  
  11.             int[] color = new int[n]; // 用来做标记  
  12.             int[] parent = new int[n]; // 用来装结果的数组  
  13.             int count = 0// 用来记录搜索个数  
  14.             System.out.println("Case " + (++k) + ":");  
  15.             // 初始化数据  
  16.             for (int i = 0; i < n; i++) {  
  17.                 a[i] = i + 1;  
  18.                 color[i] = -1;// 把未搜索的标记为-1  
  19.             }  
  20.             dfs(a, color, parent, 0, count);  
  21.             System.out.println();  
  22.         }  
  23.     }  
  24.   
  25.     private static void dfs(int[] a, int[] color, int[] parent, int u, int count) {  
  26.         count++;  
  27.         // 递归跳出的条件:次数到达了给定的的个数即数组a[]的长度;最后一个数和第一个数相加满足是素数  
  28.         if (count == a.length && isPrime(a[u] + a[0])) {  
  29.             parent[count - 1] = a[u];// ※※把最后一个结果放到parent中  
  30.             print(parent);// 输出结果  
  31.             return;  
  32.         }  
  33.         for (int v = 0; v < a.length; v++) {  
  34.             color[u] = 1// 把搜索过的标记为1  
  35.             // 满足color值为-1和当前值和下一个值相加为素数进入dfs  
  36.             if (color[v] == -1 && isPrime(a[v] + a[u])) {  
  37.                 parent[count - 1] = a[u];// ※※把满足的值放在结果数组中  
  38.                 dfs(a, color, parent, v, count);  
  39.                 color[v] = -1;// 还原标记  
  40.             }  
  41.         }  
  42.     }  
  43.   
  44.     // 输出结果  
  45.     private static void print(int[] parent) {  
  46.         for (int i = 0; i < parent.length; i++) {  
  47.             if (i < parent.length - 1) {  
  48.                 System.out.print(parent[i] + " ");  
  49.             } else {  
  50.                 System.out.println(parent[i]);  
  51.             }  
  52.         }  
  53.     }  
  54.   
  55.     // 判断是否为素数  
  56.     private static boolean isPrime(int num) {  
  57.         for (int i = 2; i * i <= num; i++) {  
  58.             if (num % i == 0) {  
  59.                 return false;  
  60.             }  
  61.         }  
  62.         return true;  
  63.     }  
  64. }  



0 0