zoukankan      html  css  js  c++  java
  • 《算法》第六章部分程序 part 5

    ▶ 书中第六章部分程序,包括在加上自己补充的代码,网络最大流 Ford - Fulkerson 算法,以及用到的流量边类和剩余流量网络类

    ● 网络最大流 Ford - Fulkerson 算法

      1 package package01;
      2 
      3 import edu.princeton.cs.algs4.StdOut;
      4 import edu.princeton.cs.algs4.FlowEdge;
      5 import edu.princeton.cs.algs4.FlowNetwork;
      6 import edu.princeton.cs.algs4.Queue;
      7 
      8 public class class01
      9 {
     10     private static final double FLOATING_POINT_EPSILON = 1E-11;
     11 
     12     private final int V;          // 顶点数
     13     private boolean[] marked;     // 已搜索顶点,marked[v] = true 表示从起点 s 到顶点 v 存在一条具有剩余流量的路径
     14     private FlowEdge[] edgeTo;    // s -> v 路径上的最后一条边
     15     private double value;         // 当前最大流量
     16 
     17     public class01(FlowNetwork G, int s, int t)
     18     {
     19         V = G.V();
     20         if (s == t || !isFeasible(G, s, t))
     21             throw new IllegalArgumentException("
    <constructor> Source == Sink || !isFeasible(G, s, t).
    ");
     22         for (value = excess(G, t); hasAugmentingPath(G, s, t);)             // 初始流量为顶点 t 净流量,只要还存在具有剩余容量的路径就要扩容
     23         {
     24             double bottle = Double.POSITIVE_INFINITY;                       // 沿着找到的路径走一遍,最小剩余容量作为扩容量
     25             for (int v = t; v != s; v = edgeTo[v].other(v))
     26                 bottle = Math.min(bottle, edgeTo[v].residualCapacityTo(v));
     27             for (int v = t; v != s; v = edgeTo[v].other(v))                 // 扩容
     28                 edgeTo[v].addResidualFlowTo(v, bottle);
     29             value += bottle;                                                // 总流量也要增加
     30         }
     31     }
     32 
     33     public double value()
     34     {
     35         return value;
     36     }
     37 
     38     public boolean inCut(int v)                                             // 顶点 v 是否在 s-切分中
     39     {
     40         return marked[v];
     41     }
     42 
     43     private boolean hasAugmentingPath(FlowNetwork G, int s, int t)  // 判断是否存在从 s 到 t 的剩余容量路径
     44     {
     45         edgeTo = new FlowEdge[G.V()];
     46         marked = new boolean[G.V()];
     47         Queue<Integer> queue = new Queue<Integer>();                // 广度优先搜索,保持所有搜索过的路径都有剩余容量
     48         for (queue.enqueue(s), marked[s] = true; !queue.isEmpty() && !marked[t];)
     49         {
     50             int v = queue.dequeue();
     51             for (FlowEdge e : G.adj(v))
     52             {
     53                 int w = e.other(v);
     54                 if (e.residualCapacityTo(w) > 0)                    // 如果取出的边关于终点 w 有剩余流量,则将其入队
     55                 {
     56                     if (!marked[w])
     57                     {
     58                         edgeTo[w] = e;
     59                         marked[w] = true;
     60                         queue.enqueue(w);
     61                     }
     62                 }
     63             }
     64         }
     65         return marked[t];                                           // 如果搜索到过 t,说明存在一条具有剩余容量的路径
     66     }
     67 
     68     private double excess(FlowNetwork G, int v)                     // 计算顶点 v 的净流量
     69     {
     70         double excess = 0.0;
     71         for (FlowEdge e : G.adj(v))                                 // 入边增加,出边减少
     72             excess += (v == e.to() ? e.flow() : -e.flow());
     73         return excess;
     74     }
     75 
     76     private boolean isFeasible(FlowNetwork G, int s, int t)         // 节点流量异常检查
     77     {
     78         for (int v = 0; v < G.V(); v++)
     79         {
     80             for (FlowEdge e : G.adj(v))
     81             {
     82                 if (e.flow() < -FLOATING_POINT_EPSILON || e.flow() > e.capacity() + FLOATING_POINT_EPSILON) // 某条边的流量异常
     83                 {
     84                     System.err.println("Edge does not satisfy capacity constraints: " + e);
     85                     return false;
     86                 }
     87             }
     88         }
     89         if (Math.abs(value + excess(G, s)) > FLOATING_POINT_EPSILON)// 当前起点净流量(<0)加上图流量非零,异常
     90         {
     91             System.err.println("Excess at source = " + excess(G, s) + "Max flow         = " + value);
     92             return false;
     93         }
     94         if (Math.abs(value - excess(G, t)) > FLOATING_POINT_EPSILON)// 当前终点净流量(>0)减去图流量非零,异常
     95         {
     96             System.err.println("Excess at sink   = " + excess(G, t) + "Max flow         = " + value);
     97             return false;
     98         }
     99         for (int v = 0; v < G.V(); v++)                             // 其他节点净流量应该为零
    100         {
    101             if (v == s || v == t)
    102                 continue;
    103             if (Math.abs(excess(G, v)) > FLOATING_POINT_EPSILON)
    104             {
    105                 System.err.println("Net flow out of " + v + " doesn't equal zero");
    106                 return false;
    107             }
    108         }
    109         return true;
    110     }
    111 
    112     public static void main(String[] args)
    113     {
    114         int V = Integer.parseInt(args[0]), E = Integer.parseInt(args[1]), s = 0, t = V - 1;
    115         FlowNetwork G = new FlowNetwork(V, E);
    116         StdOut.println(G);
    117         class01 maxflow = new class01(G, s, t);
    118         StdOut.println("Max flow from " + s + " to " + t);
    119         for (int v = 0; v < G.V(); v++)                             // 打印所有具有流量的边
    120         {
    121             for (FlowEdge e : G.adj(v))
    122             {
    123                 if ((v == e.from()) && e.flow() > 0)
    124                     StdOut.println("   " + e);
    125             }
    126         }
    127         StdOut.print("Min cut: ");                                  // 输出最小切分
    128         for (int v = 0; v < G.V(); v++)
    129             if (maxflow.inCut(v)) StdOut.print(v + " ");
    130         StdOut.println("
    Max flow value = " + maxflow.value());
    131     }
    132 }

    ● 流量边类

      1 package package01;
      2 
      3 public class class01
      4 {
      5     private static final double FLOATING_POINT_EPSILON = 1E-10;
      6 
      7     private final int v;             // 起点
      8     private final int w;             // 终点
      9     private final double capacity;   // 容量
     10     private double flow;             // 流量
     11 
     12     public class01(int inputV, int inputW, double inputCapacity)    // 三种构造函数
     13     {
     14         if (inputV < 0 || inputW < 0 || inputCapacity<0)
     15             throw new IllegalArgumentException("
    <constructor> inputV < 0 || inputW < 0 || inputCapacity < 0.
    ");
     16         v = inputV;
     17         w = inputW;
     18         capacity = inputCapacity;
     19         flow = 0.0;
     20     }
     21 
     22     public class01(int inputV, int inputW, double inputCapacity, double inputFlow)
     23     {
     24         if (inputV < 0 || inputW < 0 || inputCapacity<0 || inputFlow < 0.0 || inputFlow > inputCapacity)
     25             throw new IllegalArgumentException("
    <constructor> inputV < 0 || inputW < 0 || inputCapacity < 0 || flow < 0.0 || flow > capacity.
    ");
     26         v = inputV;
     27         w = inputW;
     28         capacity = inputCapacity;
     29         flow = inputFlow;
     30     }
     31 
     32     public class01(class01 e)
     33     {
     34         v = e.v;
     35         w = e.w;
     36         capacity = e.capacity;
     37         flow = e.flow;
     38     }
     39 
     40     public int from()
     41     {
     42         return v;
     43     }
     44 
     45     public int to()
     46     {
     47         return w;
     48     }
     49 
     50     public double capacity()
     51     {
     52         return capacity;
     53     }
     54 
     55     public double flow()
     56     {
     57         return flow;
     58     }
     59 
     60     public int other(int vertex)
     61     {
     62         if (vertex == v)
     63             return w;
     64         else if (vertex == w)
     65             return v;
     66         throw new IllegalArgumentException("
    <other> invalid endpoint.
    ");
     67     }
     68 
     69     public double residualCapacityTo(int vertex)    // 计算一条边关于某个顶点的流通能力
     70     {
     71         if (vertex == v)                            // 起点,返回边的现有流量
     72             return flow;
     73         else if (vertex == w)                       // 终点,返回边的剩余容量
     74             return capacity - flow;
     75         throw new IllegalArgumentException("
    <residualCapacityTo> invalid endpoint.
    ");
     76     }
     77 
     78     public void addResidualFlowTo(int vertex, double delta)         // 改变边的流量
     79     {
     80         if (delta < 0.0)
     81             throw new IllegalArgumentException("
    <addResidualFlowTo> delta < 0.0.
    ");
     82         if (vertex == v)                            // 起点,边流量减少
     83             flow -= delta;
     84         else if (vertex == w)                       // 终点,边流量增加
     85             flow += delta;
     86         else
     87             throw new IllegalArgumentException("
    <addResidualFlowTo> invalid endpoint.
    ");
     88         if (Math.abs(flow) <= FLOATING_POINT_EPSILON)               // 流量归零
     89             flow = 0;
     90         if (Math.abs(flow - capacity) <= FLOATING_POINT_EPSILON)    // 流量达到容量
     91             flow = capacity;
     92         if (flow < 0.0)                                             // 流量异常
     93             throw new IllegalArgumentException("
    <addResidualFlowTo> flow <0.
    ");
     94         if (flow > capacity)
     95             throw new IllegalArgumentException("
    <addResidualFlowTo> flow > capacity.
    ");
     96     }
     97 
     98     public String toString()
     99     {
    100         return v + "->" + w + " " + flow + "/" + capacity;
    101     }
    102 
    103     public static void main(String[] args)
    104     {
    105         class01 e = new class01(12, 23, 4.56);
    106         StdOut.println(e);
    107     }
    108 }

    ● 剩余流量网络类

      1 package package01;
      2 
      3 import edu.princeton.cs.algs4.In;
      4 import edu.princeton.cs.algs4.StdOut;
      5 import edu.princeton.cs.algs4.StdRandom;
      6 import edu.princeton.cs.algs4.FlowEdge;
      7 import edu.princeton.cs.algs4.Bag;
      8 
      9 public class class01
     10 {
     11     private static final String NEWLINE = System.getProperty("line.separator");
     12 
     13     private final int V;
     14     private int E;
     15     private Bag<FlowEdge>[] adj;
     16 
     17     public class01(int inputV)
     18     {
     19         if (V < 0)
     20             throw new IllegalArgumentException("
    <constructor> inputV < 0.
    ");
     21         V = inputV;
     22         E = 0;
     23         adj = (Bag<FlowEdge>[]) new Bag[V];
     24         for (int v = 0; v < V; v++)
     25             adj[v] = new Bag<FlowEdge>();
     26     }
     27 
     28     public class01(int inputV, int inputE)
     29     {
     30         this(inputV);
     31         if (E < 0)
     32             throw new IllegalArgumentException("
    <constructor> inputE < 0.
    ");
     33         for (int i = 0; i < E; i++)
     34             addEdge(new FlowEdge(StdRandom.uniform(V), StdRandom.uniform(V), StdRandom.uniform(100)));
     35     }
     36 
     37     public class01(In in)
     38     {
     39         this(in.readInt());
     40         E = in.readInt();
     41         for (int i = 0; i < E; i++)
     42             addEdge(new FlowEdge(in.readInt(), in.readInt(), in.readDouble()));
     43     }
     44 
     45     public int V()
     46     {
     47         return V;
     48     }
     49 
     50     public int E()
     51     {
     52         return E;
     53     }
     54 
     55     public void addEdge(FlowEdge e)     // 添加一条边
     56     {
     57         adj[e.from()].add(e);
     58         adj[e.to()].add(e);
     59         E++;
     60     }
     61 
     62     public Iterable<FlowEdge> adj(int v)// 一个顶点上出边的迭代器,就是该顶点的单链表
     63     {
     64         return adj[v];
     65     }
     66 
     67     public Iterable<FlowEdge> edges()   // 所有边的迭代器,和搜集所有顶点处的出边
     68     {
     69         Bag<FlowEdge> list = new Bag<FlowEdge>();
     70         for (int v = 0; v < V; v++)
     71         {
     72             for (FlowEdge e : adj(v))
     73             {
     74                 if (e.to() != v)
     75                     list.add(e);
     76             }
     77         }
     78         return list;
     79     }
     80 
     81     public String toString()
     82     {
     83         StringBuilder s = new StringBuilder();
     84         s.append(V + " " + E + NEWLINE);
     85         for (int v = 0; v < V; v++)
     86         {
     87             s.append(v + ":  ");
     88             for (FlowEdge e : adj[v])
     89                 if (e.to() != v) s.append(e + "  ");
     90             s.append(NEWLINE);
     91         }
     92         return s.toString();
     93     }
     94 
     95     public static void main(String[] args)
     96     {
     97         In in = new In(args[0]);
     98         class01 G = new class01(in);
     99         StdOut.println(G);
    100     }
    101 }
  • 相关阅读:
    用List绑定GridView的简单辅助类
    宋忠玲(帮读者名字作诗)
    [转帖]每天看一遍,释怀所有难过
    30岁,我们怎么赢?
    柴门远望
    创业,不要被那些成功人士所忽悠
    一只海燕飞过来
    成功者都在用的“成功咒语”
    诗歌复兴
    游熊猫基地有感
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9945113.html
Copyright © 2011-2022 走看看