• 《算法》第四章部分程序 part 18


    ▶ 书中第四章部分程序,包括在加上自己补充的代码,在有权有向图中寻找环,Bellman - Ford 算法求最短路径,套汇算法

    ● 在有权有向图中寻找环

      1 package package01;
      2 
      3 import edu.princeton.cs.algs4.StdOut;
      4 import edu.princeton.cs.algs4.StdRandom;
      5 import edu.princeton.cs.algs4.DirectedEdge;
      6 import edu.princeton.cs.algs4.EdgeWeightedDigraph;
      7 import edu.princeton.cs.algs4.Stack;
      8 
      9 public class class01
     10 {
     11     private boolean[] marked;
     12     private DirectedEdge[] edgeTo;
     13     private boolean[] onStack;              // 各顶点当前是否在搜索栈中,递归回退时要清空
     14     private Stack<DirectedEdge> cycle;      // 存储环,若空则表示图中不存在环
     15 
     16     public class01(EdgeWeightedDigraph G)
     17     {
     18         marked = new boolean[G.V()];
     19         edgeTo = new DirectedEdge[G.V()];
     20         onStack = new boolean[G.V()];
     21         for (int v = 0; v < G.V(); v++)
     22         {
     23             if (!marked[v])
     24                 dfs(G, v);
     25         }
     26     }
     27 
     28     private void dfs(EdgeWeightedDigraph G, int v)
     29     {
     30         marked[v] = true;
     31         onStack[v] = true;
     32         for (DirectedEdge e : G.adj(v))
     33         {
     34             int w = e.to();
     35             if (cycle != null)              // 已经有环了
     36                 return;
     37             if (!marked[w])
     38             {
     39                 edgeTo[w] = e;
     40                 dfs(G, w);
     41             }
     42             else if (onStack[w])            // 该点已经遍历过,且在栈中,即有环
     43             {
     44                 cycle = new Stack<DirectedEdge>();
     45                 DirectedEdge f = e;
     46                 for (; f.from() != w; f = edgeTo[f.from()]) // 回退搜索栈压入 cycle 中,直到该环在搜索栈中的首元素 w 处
     47                     cycle.push(f);
     48                 cycle.push(f);              // 压入环在搜索栈中的首元素 w
     49                 return;
     50             }
     51         }
     52         onStack[v] = false;                 // 递归回退时栈要清空,但 marked 不清空
     53     }
     54 
     55     public boolean hasCycle()
     56     {
     57         return cycle != null;
     58     }
     59 
     60     public Iterable<DirectedEdge> cycle()
     61     {
     62         return cycle;
     63     }
     64 
     65     public static void main(String[] args)
     66     {
     67         int V = Integer.parseInt(args[0]);  // 新建有边权有向图 G(E,V),再添加 F 条边
     68         int E = Integer.parseInt(args[1]);
     69         int F = Integer.parseInt(args[2]);
     70         EdgeWeightedDigraph G = new EdgeWeightedDigraph(V);
     71         int[] vertices = new int[V];
     72         for (int i = 0; i < V; i++)
     73             vertices[i] = i;
     74         StdRandom.shuffle(vertices);
     75         for (int i = 0; i < E; i++)
     76         {
     77             int v = 1, w = 0;
     78             for (; v >= w; v = StdRandom.uniform(V), w = StdRandom.uniform(V));
     79             double weight = StdRandom.uniform();
     80             G.addEdge(new DirectedEdge(v, w, weight));
     81         }
     82         for (int i = 0; i < F; i++)
     83         {
     84             int v = StdRandom.uniform(V), w = StdRandom.uniform(V);
     85             double weight = StdRandom.uniform(0.0, 1.0);
     86             G.addEdge(new DirectedEdge(v, w, weight));
     87         }
     88 
     89         StdOut.println(G);                  // 原图
     90         class01 finder = new class01(G);    // 搜索环
     91         if (finder.hasCycle())
     92         {
     93             StdOut.print("Cycle: ");
     94             for (DirectedEdge e : finder.cycle())
     95                 StdOut.print(e + " ");
     96             StdOut.println();
     97         }
     98         else
     99             StdOut.println("No directed cycle");
    100     }
    101 }

    ● Bellman - Ford 算法求最短路径

      1 package package01;
      2 
      3 import edu.princeton.cs.algs4.In;
      4 import edu.princeton.cs.algs4.StdOut;
      5 import edu.princeton.cs.algs4.DirectedEdge;
      6 import edu.princeton.cs.algs4.EdgeWeightedDigraph;
      7 import edu.princeton.cs.algs4.EdgeWeightedDirectedCycle;
      8 import edu.princeton.cs.algs4.Stack;
      9 import edu.princeton.cs.algs4.Queue;
     10 
     11 public class class01
     12 {
     13     private double[] distTo;                // 起点到各顶点的距离
     14     private DirectedEdge[] edgeTo;          // 起点到各顶点的最后一条边
     15     private boolean[] onQueue;              // 各顶点当前是否在搜索队中
     16     private Queue<Integer> queue;           // 搜索队列
     17     private int cost;                       // 调用函数 relax 的次数
     18     private Iterable<DirectedEdge> cycle;   // 存储负环,若空则表示图中不存在负环
     19 
     20     public class01(EdgeWeightedDigraph G, int s)
     21     {
     22         distTo = new double[G.V()];
     23         edgeTo = new DirectedEdge[G.V()];
     24         onQueue = new boolean[G.V()];
     25         for (int v = 0; v < G.V(); v++)
     26             distTo[v] = Double.POSITIVE_INFINITY;
     27         distTo[s] = 0.0;
     28         queue = new Queue<Integer>();
     29         for (queue.enqueue(s), onQueue[s] = true; !queue.isEmpty() && !hasNegativeCycle();) // 存在负环则停止搜索
     30         {
     31             int v = queue.dequeue();                //  每次从搜索队列中拿走一个顶点,松弛以该顶点为起点的边
     32             onQueue[v] = false;
     33             relax(G, v);
     34         }
     35     }
     36 
     37     private void relax(EdgeWeightedDigraph G, int v)
     38     {
     39         for (DirectedEdge e : G.adj(v))
     40         {
     41             int w = e.to();
     42             if (distTo[w] > distTo[v] + e.weight()) // 加入这条边会使起点到 w 的距离变短
     43             {
     44                 distTo[w] = distTo[v] + e.weight();
     45                 edgeTo[w] = e;
     46                 if (!onQueue[w])                    // 注意若 w 已经在搜索队列中则不做任何改变
     47                 {
     48                     queue.enqueue(w);
     49                     onQueue[w] = true;
     50                 }
     51             }
     52             if (cost++ % G.V() == 0)                // 每当松弛了 V 的倍数次时检查是否存在负环
     53             {
     54                 findNegativeCycle();
     55                 if (hasNegativeCycle())
     56                     return;
     57             }
     58         }
     59     }
     60 
     61     private void findNegativeCycle()                // 利用类 EdgeWeightedDirectedCycle 来找环
     62     {
     63         int V = edgeTo.length;
     64         EdgeWeightedDigraph spt = new EdgeWeightedDigraph(V);
     65         for (int v = 0; v < V; v++)
     66         {
     67             if (edgeTo[v] != null)
     68                 spt.addEdge(edgeTo[v]);
     69         }
     70         EdgeWeightedDirectedCycle finder = new EdgeWeightedDirectedCycle(spt);
     71         cycle = finder.cycle();
     72     }
     73 
     74     public boolean hasNegativeCycle()
     75     {
     76         return cycle != null;
     77     }
     78 
     79     public Iterable<DirectedEdge> negativeCycle()
     80     {
     81         return cycle;
     82     }
     83 
     84     public boolean hasPathTo(int v)
     85     {
     86         return distTo[v] < Double.POSITIVE_INFINITY;
     87     }
     88 
     89     public double distTo(int v)
     90     {
     91         if (hasNegativeCycle())
     92             throw new UnsupportedOperationException("
    <distTo> Negative cost cycle exists.
    ");
     93         return distTo[v];
     94     }
     95 
     96     public Iterable<DirectedEdge> pathTo(int v)
     97     {
     98         if (hasNegativeCycle())
     99             throw new UnsupportedOperationException("
    <pathTo> Negative cost cycle exists.
    ");
    100         if (!hasPathTo(v))
    101             return null;
    102         Stack<DirectedEdge> path = new Stack<DirectedEdge>();
    103         for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()])
    104             path.push(e);
    105         return path;
    106     }
    107 
    108     public static void main(String[] args)
    109     {
    110         In in = new In(args[0]);
    111         int s = Integer.parseInt(args[1]);
    112         EdgeWeightedDigraph G = new EdgeWeightedDigraph(in);
    113         class01 sp = new class01(G, s);
    114         if (sp.hasNegativeCycle())
    115         {
    116             for (DirectedEdge e : sp.negativeCycle())
    117                 StdOut.println(e);
    118         }
    119         else
    120         {
    121             for (int v = 0; v < G.V(); v++)
    122             {
    123                 if (sp.hasPathTo(v))
    124                 {
    125                     StdOut.printf("%d to %d (%5.2f)  ", s, v, sp.distTo(v));
    126                     for (DirectedEdge e : sp.pathTo(v))
    127                         StdOut.print(e + "   ");
    128                     StdOut.println();
    129                 }
    130                 else
    131                     StdOut.printf("%d to %d           no path
    ", s, v);
    132             }
    133         }
    134     }
    135 }

     ● 套汇,本质是寻找负环

     1 package package01;
     2 
     3 import edu.princeton.cs.algs4.StdIn;
     4 import edu.princeton.cs.algs4.StdOut;
     5 import edu.princeton.cs.algs4.DirectedEdge;
     6 import edu.princeton.cs.algs4.EdgeWeightedDigraph;
     7 import edu.princeton.cs.algs4.BellmanFordSP;
     8 
     9 public class class01
    10 {
    11     private class01() {}
    12 
    13     public static void main(String[] args)
    14     {
    15         int V = StdIn.readInt();                            // 顶点数
    16         String[] name = new String[V];
    17         EdgeWeightedDigraph G = new EdgeWeightedDigraph(V);
    18         for (int v = 0; v < V; v++)                         // 建图
    19         {
    20             name[v] = StdIn.readString();
    21             for (int w = 0; w < V; w++)
    22             {
    23                 double rate = StdIn.readDouble();
    24                 DirectedEdge e = new DirectedEdge(v, w, -Math.log(rate));// 汇率取负对数,x1x2x3 < 1 -> -logx1 -logx2 -logx3 < 0
    25                 G.addEdge(e);
    26             }
    27         }
    28         BellmanFordSP spt = new BellmanFordSP(G, 0);        // 用 BF 算法找负环
    29         if (spt.hasNegativeCycle())
    30         {
    31             double stake = 1000.0;
    32             for (DirectedEdge e : spt.negativeCycle())
    33             {
    34                 StdOut.printf("%10.5f %s ", stake, name[e.from()]);
    35                 stake *= Math.exp(-e.weight());
    36                 StdOut.printf("= %10.5f %s
    ", stake, name[e.to()]);
    37             }
    38         }
    39         else
    40             StdOut.println("No arbitrage opportunity");
    41     }
    42 }
  • 相关阅读:
    防窜货下加密锁使用常见问题
    SQL Server 2000/2005/2008 触发器的管理和查看
    列表显示时,部分凭证会分两行显示,且不能删除
    JDBC 连接 带实例名的SQL Server
    登录软件提示:读取数据源出现错误,pkcs7填充无效,无法被移除
    完美卸载SQL Server 2008的方案
    彻底卸载(删除)SQL server2000
    NCV5取消:授权数到达,或者许可证过期提示的秘诀
    SQL Server日志清空方法 .
    第二天 一列布局
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9836335.html
Copyright © 2020-2023  润新知