• 图实践经典问题一览


    图算是数据结构中比较难的问题,但是在实际中解决的问题也更多。

    其中,在图结构中涉及的问题主要有:

    图的存储:

    • 邻接表(Adjacency list):为每个节点建立一个链表存放与之连接的点.
    • 邻接矩阵(Adjacency matrix):n*n的矩阵,有边的是1,无边的是0.

    最短路径:

    • Dijkstra:记录起点能够到达的所有节点的最短路径,这样,我们要找的终点一定在其中啊。
      • DIST(w) = min(DIST(w), DIST(u) + c(u, w))
      • 代码实现示例:
      • package com.realise;
        
        import java.util.Arrays;
        
        public class Dijkstra {
            static int max = 10000;
            
            public static int[] dijkstra(int[][] edge) {
                int n = edge.length;
                int[] res = new int[n];
                for(int i=0; i<n; i++)
                    res[i] = edge[0][i];
                for(int i=0; i<n; i++) {
                    for(int j=0; j<n; j++) {
                        if(res[j] + edge[j][i] < res[i])
                            res[i] = res[j] + edge[j][i];
                    }
                }
                return res;
            }
            
            
            public static void main(String[] args) {
                // TODO Auto-generated method stub
                int[][] edge = {
                        {0,20,50,30,max, max, max},
                        {max,0,25,max,max,70,max},
                        {max,max,0,40,25,50,max},
                        {max,max,max,0,55,max,max},
                        {max,max,max,max,0,10,70},
                        {max,max,max,max,max,0,50},
                        {max,max,max,max,max,max,0}
                };
                int[] res = dijkstra(edge);
                System.out.println(Arrays.toString(res));
            }
        
        }
        View Code
    • Floyd:又称插点法,可以寻找任意两点间的最短路径,允许图中带负权值的边,但不允许包含负权值的边组成的回路。
      • 代码实现示例:
      • package com.realise;
        
        /**
         * Floyd算法的实现
         * @author 
         *
         */
        public class Floyd {
            static int Max = 1000;
            
            public static int[][] floydRealise(int[][] edge) {
                int n = edge.length;
                int[][] a = new int[n][n];
                int[][] path = new int[n][n];
                //Initialize 
                for(int i=0; i<n; i++) {
                    for(int j=0; j<n; j++) {
                        a[i][j] = edge[i][j];
                        if(i != j && edge[i][j] < Max)
                            path[i][j] = i;
                        else
                            path[i][j] = 0;
                    }
                }
                //T(O) = O(n3)
                for(int i=0; i<n; i++) {
                    for(int j=0; j<n; j++) {
                        for(int k=0; k<n; k++) {
                            if(a[j][i] + a[i][k] < a[j][k]) {
                                a[j][k] = a[j][i] + a[i][k];
                                path[j][k] = path[i][k];
                            }
                        }
                    }
                }
                
                return a;
                
            }
            
            public static void main(String[] args) {
                // TODO Auto-generated method stub
             int[][] edge = {
                        {0,1,Max,4},
                        {Max,0,9,2},
                        {3,5,0,8},
                        {Max, Max, 6,0}
                };
                int[][] res = floydRealise(edge);
                for(int i=0; i<res.length; i++) {
                    for(int j=0; j<res.length; j++)
                        System.out.print(res[i][j] + " ");
                    System.out.println();
                }
            }
        
        }
        View Code

    最小生成树

    • Prim算法:A为要求的生成树,将要计入到A中的下一条边(u, v),应是E种一条不在A中且最小成本的边。
      •            
      • 代码示例:华为的一道笔试题,使用Prim解决的,作为本个算法的示例程序:
      • import java.util.Scanner;
        import java.util.Vector;
        
        /**
         * 沿海有N个岛屿,为方便岛与岛之间的沟通,现规划对这些岛屿进行建桥,
         * 建桥的消耗和岛屿之间的距离成正比,如何规划才能使每个桥梁都能连通,且消耗最少
         * @author 
         *
         */
        public class Main {
            
            public static int prim(int[][] val) {
                if(val == null || val.length == 0 || val.length == 1)
                    return 0;
                boolean[] visited = new boolean[val.length];
                for(int i=0; i<visited.length; i++)
                    visited[i] = false;
                visited[0] = true;
                int count = 1;
                int res = 0;
                Vector<Integer> v = new Vector<Integer>();
                v.add(0);
                do {
                    int weight = Integer.MAX_VALUE;
                    int temp = -1;
                    for(Integer i : v) {
                        for(int j=0; j<val.length; j++) {
                            if(j != i && visited[j] == false && val[i][j] < weight) {
                                weight = val[i][j];
                                temp = j;
                            }
                        }
                    }
                    res += weight;
                    v.add(temp);
                    count++;
                    visited[temp] = true;
                } while(count < val.length);
                return res;
            }
            
            
            
            public static void main(String[] args) {
                /*input example:
                3
                0 990 692
                990 0 179
                692 179 0
                */
                Scanner sc = new Scanner(System.in);
                int N = sc.nextInt();
                sc.nextLine();
                String[] arr = new String[N];
                for(int i=0; i<N; i++) 
                    arr[i] = sc.nextLine();
                
                int[][] val = new int[N][N];
                for(int i=0; i<N; i++) {
                    String[] temp = arr[i].split(" ");
                    for(int j=0; j<temp.length; j++) 
                        val[i][j] = Integer.parseInt(temp[j]);
                }
                
        //        int[][] val = {{0, 10, 1000, 30, 100},{10, 0, 50, 1000, 1000}, {1000, 50, 0, 20, 10},
        //                {30, 1000, 20, 0, 60},{100, 1000, 10, 60, 0}};
                System.out.println(prim(val));
                
            }
        
        }
        View Code 
    •  Kruskal算法:将图中所有边的权重按大小排序,然后在每次添加放入边中以不构成回路为前提,每次选择一条权重最小的边加入生成树中。
      • 为了快速判断候选边e的加入是否会形成环,可以使用并查集。时间复杂度为:O(eloge).

    图的搜索(遍历):其中要特别注意隐式图的搜索,一些问题乍一看可能不是图的问题,但是其实可以用图的方法解决!!!

    • 广度优先搜索BFS:辅助数据结构为队列,与树的层次遍历类似
    • 深度优先搜索DFS:辅助数据结构为,与树的先序/中序/后序遍历类似
    • 隐式图:在实践中,往往一看不是关于图的问题,但如果给定一个起始状态和一些规则,求解决方案的问题:往往可以根据这些规则,将各个状态建立边,然后BFS/DFS搜索方法,在解空间中搜索。

    几个经典的问题:

    • 单词变换问题Word Ladder。http://www.cnblogs.com/little-YTMM/p/5502954.html
      • Given a pattern and a string str, find if str follows the same pattern.

        Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty word in str.

        Examples:

        1. pattern = "abba", str = "dog cat cat dog" should return true.
        2. pattern = "abba", str = "dog cat cat fish" should return false.
        3. pattern = "aaaa", str = "dog cat cat dog" should return false.
        4. pattern = "abba", str = "dog dog dog dog" should return false.
        代码如下:
        • public class Solution {
              public boolean wordPattern(String pattern, String str) {
                      Map<Character, String> map = new HashMap<Character, String> ();
                      Set<String> set = new HashSet<String>();
                      char[] ch = pattern.toCharArray();
                      String[] strr = str.split(" ");
                      if(ch.length != strr.length)
                          return false;
                      for(int i=0; i<ch.length; i++) {
                          if(!map.containsKey(ch[i]) && !set.contains(strr[i])) {
                              map.put(ch[i], strr[i]);
                              set.add(strr[i]);
                          } else {
                              if(set.contains(strr[i]) && !map.containsKey(ch[i]))
                                  return false;
                              if(!map.get(ch[i]).equals(strr[i]))
                                  return false;
                          }
                      }
                      return true;
              }
              
          }
          View Code
    • 周围区域问题。http://www.cnblogs.com/little-YTMM/p/5480942.html
        • 代码:
        • import java.util.LinkedList;
          import java.util.Queue;
          
          class Node {
              int x;
              int y;
              public Node(int x, int y) {
                  this.x = x;
                  this.y = y;
              }
          }
          class Regions {
              private int[] rowdi = {-1, 1, 0, 0};
              private int[] coldi = {0, 0, -1, 1};
              
              /**
               * BFS. 
               * Search begin from the edge to the interior. 
               * @param val
               * @return
               */
              public int[][] check(int[][] val) {
                  if(val == null || val.length == 0 || val[0].length == 0)
                      return val;
                  Queue<Node> q = new LinkedList<Node>();
                  int row = val.length;
                  int col = val[0].length;
                  for(int i=0; i<row; i++) {
                      if(val[i][0] == 0) {
                          Node n = new Node(i, 0);
                          q.add(n);
                          val[i][0] = 2;
                      }
                      if(val[i][col-1] == 0) {
                          Node n = new Node(i, col-1);
                          q.add(n);
                          val[i][col-1] = 2;
                      }
                  }
                  for(int j=1; j<col-1; j++) {
                      if(val[0][j] == 0) {
                          Node n = new Node(0, j);
                          q.add(n);
                          val[0][j] = 2;
                      }
                      if(val[row-1][j] == 0) {
                          Node n = new Node(row-1, j);
                          q.add(n);
                          val[row-1][j] = 2;
                      }
                  }
                  while(!q.isEmpty()) {
                      Node n = q.remove();
                      for(int i=0; i<rowdi.length; i++) {
                          if( n.x+rowdi[i]<row && n.y+coldi[i] < col
                                  && n.x+rowdi[i] >= 0 && n.y+coldi[i] >= 0) {
                              if(val[n.x+rowdi[i]][n.y+coldi[i]] == 0) {
                                  Node t = new Node(n.x+rowdi[i], n.y+coldi[i]);
                                  q.add(t);
                                  val[n.x+rowdi[i]][n.y+coldi[i]] = 2;
                              }
                          }
                      }
                  }
                  for(int i=0; i<row; i++) {
                      for(int j=0; j<col; j++) {
                          if(val[i][j] == 2)
                              val[i][j] = 0;
                          else if(val[i][j] == 0)
                              val[i][j] = 1;
                      }
                  }
                  return val;
              }
          }
          
          
          public class SurroundedRegions {
          
              public static void main(String[] args) {
                  int[][] val = {
                          {1,1,1,1,1},
                          {1,0,0,1,0},
                          {1,1,1,1,0},
                          {1,0,1,0,0},
                          {1,1,1,1,1}};
                  Regions region = new Regions();
                  int[][] res = region.check(val);
                  for(int i=0; i<res.length; i++) {
                      for(int j=0; j<res[0].length; j++)
                          System.out.print(res[i][j] + " ");
                      System.out.println();
                  }
              }
          
          }
          View Code
    • 八皇后问题。http://www.cnblogs.com/little-YTMM/p/5478140.html
        • 代码:
        • package com.eight;
          
          import java.util.ArrayList;
          import java.util.Arrays;
          
          class EightQueen {
              private int N; //The number of queens.
              private boolean[] column;
              private boolean[] maind;
              private boolean[] secondaryd;
              private ArrayList<int[]> result = new ArrayList<int[]>();
              
              
              
              /**
               * Initial the column, main diagonal, secondary diagonal to false,
               * which means there is no queen everywhere.
               * @param N
               */
              public void initQ(int N) {
                  this.N = N;
                  column = new boolean[N];
                  maind = new boolean[2 * N - 1];
                  secondaryd = new boolean[2 * N - 1];
                  int i = 0;
                  for(i=0; i<column.length; i++)
                      column[i] = false;
                  for(i=0; i<maind.length; i++)
                      maind[i] = false;
                  for(i=0; i<secondaryd.length; i++)
                      secondaryd[i] = false;
              }
              
              /**
               * the main function of lay queens.
               */
              public void queens() {
                  int[] path = new int[N];
                  calcQueen(path, 0);
              }
          
              private void calcQueen(int[] path, int row) {
                  // TODO Auto-generated method stub
                  if(row == N) {
                      result.add(path);
                      System.out.println(Arrays.toString(path));
                      return;
                  }
                  for(int col=0; col<N; col++) {
                      if(canLay(row, col)) {
                          path[row] = col;
                          column[col] = true;
                          maind[row-col+N-1] = true;
                          secondaryd[row+col] = true;
                          calcQueen(path, row+1);
                          
                          //BackTracking, important!!
                          column[col] = false;
                          maind[row-col+N-1] = false;
                          secondaryd[row+col] = false;
                      }
                  }
              }
          
              /**
               * Judge if the position can lay a queen.
               * @param row
               * @param col
               * @return
               */
              private boolean canLay(int row, int col) {
                  // TODO Auto-generated method stub
                  return (!column[col] && !secondaryd[row+col] && !maind[row-col+N-1]);
              }
              
              
              public ArrayList<int[]> getResult() {
                  return result;
              }
          }
          
          
          
          public class Queens {
          
              public static void main(String[] args) {
                  EightQueen q = new EightQueen();
                  q.initQ(8); // It is a eight queens problem.
                  q.queens();
                  
              }
          
          }
          //Some output instances:
          [0, 4, 7, 5, 2, 6, 1, 3]
          [0, 5, 7, 2, 6, 3, 1, 4]
          [0, 6, 3, 5, 7, 1, 4, 2]
          [0, 6, 4, 7, 1, 3, 5, 2]
          [1, 3, 5, 7, 2, 0, 6, 4]
          [1, 4, 6, 0, 2, 7, 5, 3]
          [1, 4, 6, 3, 0, 7, 5, 2]
          [1, 5, 0, 6, 3, 7, 2, 4]
          [1, 5, 7, 2, 0, 3, 6, 4]
          [1, 6, 2, 5, 7, 4, 0, 3]
          [1, 6, 4, 7, 0, 3, 5, 2]
          [1, 7, 5, 0, 2, 4, 6, 3]
          [2, 0, 6, 4, 7, 1, 3, 5]
          View Code
    • 数独问题。http://www.cnblogs.com/little-YTMM/p/5507841.html
        • 代码:
        • import java.util.Stack;
          
          class Help {
              int row;
              int col;
              int val;
          }
          public class Sudoku {
          
              /**
               * Use stack store the roads.
               * @param chess
               * @return
               */
              public static int[][] getSudoku(int[][] chess) {
                  Stack<Help> stack = new Stack<Help>();
                  int val = -1;
                  for(int i=0; i<9; i++) {
                      for(int j=0; j<9; j++) {
                          if(chess[i][j] != 0)
                              continue;
                          boolean flag = false;
                          int k;
                          if(val == -1)
                              k = 0;
                          else 
                              k = val+1;
                          for(; k<10; k++) {
                              if(isValid(k, i, j, chess)) {
                                  Help h = new Help();
                                  h.row = i;
                                  h.col = j;
                                  h.val = k;
                                  stack.add(h);
                                  chess[i][j] = k;
                                  val = -1;
                                  flag = true;
                                  
                              }
                              if(flag == true)
                                  k = 10;
                          }
                          if(flag == false && !stack.isEmpty()) { //There is no road, backtracking
                              Help h = stack.pop();
                              i = h.row;
                              j = h.col-1;
                              val = h.val;
                              chess[i][j+1] = 0;
                          }
                      }
                  }
                  return chess;
              }
              
              /**
               * Judge if it is valid when chess[row][col] = k.
               * @param k
               * @param row
               * @param col
               * @param chess
               * @return
               */
              private static boolean isValid(int k, int row, int col, int[][] chess) {
                  for(int i=0; i<9; i++)
                      if(chess[row][i] == k)
                          return false;
                  for(int i=0; i<9; i++) 
                      if(chess[i][col] == k)
                          return false;
                  int r = row/3, c = col/3;
                  for(int i=r*3; i<r*3+3; i++) {
                      for(int j=c*3; j<c*3+3; j++) {
                          if(chess[i][j] == k)
                              return false;
                      }
                  }
                  return true;
              }
          
          
              public static void main(String[] args) {
                  // TODO Auto-generated method stub
                  int[][] a = {
                          {0,4,2,0,6,3,0,0,9},
                          {6,0,0,0,1,0,0,0,5},
                          {3,0,0,0,2,0,4,8,0},
                          {1,0,0,5,0,2,6,0,8},
                          {4,0,0,0,0,7,0,0,1},
                          {9,0,5,6,0,0,0,0,7},
                          {0,3,6,0,5,0,0,0,2},
                          {2,0,0,0,7,0,0,0,4},
                          {7,0,0,2,9,0,8,5,0}
                          
                      };
                  int[][] res = getSudoku(a);
                  for(int i=0; i<9; i++) {
                      for(int j=0; j<9; j++)
                          System.out.print(res[i][j] + " ");
                      System.out.println();
                  }
              }
          
          }
          View Code
    • 所有括号的匹配问题。http://www.cnblogs.com/little-YTMM/p/5505522.html

        • 代码:
        • /**
               * Given the number N, return all of the correct brackets.
               * @param n
               * @return
               */
              @SuppressWarnings("unchecked")
              public static ArrayList<String> getBracketsOfN(int n) {
                  @SuppressWarnings("rawtypes")
                  ArrayList[] dp = new ArrayList[n+1];
                  for(int i=0; i<dp.length; i++)
                      dp[i] = new ArrayList<String>();
                  dp[0].add("");
                  dp[1].add("()");
                  if(n == 0) 
                      return dp[0];
                  if(n == 1) 
                      return dp[1];
                  int count = 2;
                  while(count < n+1) {
                      ArrayList<String> lcount = dp[count];
                      for(int i=0; i<count; i++) {
                          ArrayList<String> l1 = dp[i];
                          ArrayList<String> l2 = dp[count-i-1];
                          for(int j=0; j<l1.size(); j++) {
                              for(int k=0; k<l2.size(); k++) {
                                  StringBuffer sb = new StringBuffer();
                                  sb.append(l1.get(j));
                                  sb.append("(");
                                  sb.append(l2.get(k));
                                  sb.append(")");
                                  lcount.add(sb.toString());
                              }
                          }
                      }
                      dp[count++] = lcount;
                  }
                  return dp[n];
              }
          View Code
  • 相关阅读:
    关于asp.net页面自定义404错误码返回302的最新解决方法
    基于sharpdevelop核心和ArcEngine打造插件式桌面GIS应用(概述)
    WPF自定义控件踩坑记录,用户自定义控件 绑定后台定义的 命令 依赖项属性 注意事项 静态
    WPF C# 以非独占式读取本地图片
    C#DataGridView控件60招(一)
    用TEXT文件做数据源
    boost智能指针
    linux下安装boost库
    ASP/ASP.NET程序设计电子书专题下载
    Highcharts 点击多选框取消,添加数据上绑定最大,最小值和图例上绑定提示框数据
  • 原文地址:https://www.cnblogs.com/little-YTMM/p/5510245.html
Copyright © 2020-2023  润新知