Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

Minimum Cost Flow

Find the minimum cost to send a certain amount of flow through a flow network.

The flow network is a directed graph where each edge $e$ has capacity $c(e)$ and cost $d(e)$. Each edge $e$ can send an amount of flow $f(e)$ where $f(e) \leq c(e)$. Find the minimum value of $\sum_{e} (f(e) \times d(e))$ to send an amount of flow $F$ from source $s$ to sink $t$.

Input

A flow network $G(V,E)$ is given in the following format.

$|V|\;|E|\;F$

$u_0\;v_0\;c_0\;d_0$

$u_1\;v_1\;c_1\;d_1$

:

$u_{|E|1}\;v_{|E|-1}\;c_{|E|-1}\;d_{|E|-1}$

$|V|$, $|E|$, $F$ are the number of vertices, the number of edges, and the amount of flow of the flow network respectively. The vertices in $G$ are named with the numbers $0, 1,..., |V|−1$. The source is $0$ and the sink is $|V|−1$.

$u_i$, $v_i$, $c_i$, $d_i$ represent $i$-th edge of the flow network. A pair of $u_i$ and $v_i$ denotes that there is an edge from $u_i$ to $v_i$, and $c_i$ and $d_i$ are the capacity and the cost of $i$-th edge respectively.

Output

Print the minimum value in a line. If it is impossible to send the flow from the source $s$ to the sink $t$, print -1.

Constraints

2 ≤ $|V|$ ≤ 100

1 ≤ $|E|$ ≤ 1000

0 ≤ $F$ ≤ 1000

0 ≤ $c_i$, $d_i$ ≤ 1000

$u_i$ $\ne$ $v_i$

If there is an edge from vertex $x$ to vertex $y$, there is no edge from vertex $y$ to vertex $x$.

Sample Input

4 5 2
0 1 2 1
0 2 1 2
1 2 1 1
1 3 1 3
2 3 2 1

Sample Output

6

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace santa2019
{
    struct Data
    {
        public int NextCost;
        public int To;

        public Data(int nextCost, int to)
        {
            NextCost = nextCost;
            To = to;
        }
    }

    class Edge
    {
        public int To;
        public int Cap;
        public int Cost;
        public int Rev;
        public bool IsRev;
    };

    class Prog
    {
        static void Main()
        {
            int V, E, F;
            {
                var line = Console.ReadLine();
                var values = line.Split(' ');
                V = int.Parse(values[0]);
                E = int.Parse(values[1]);
                F = int.Parse(values[2]);
            }
            PrimalDual g = new PrimalDual(V);
            for (int i = 0; i < E; i++)
            {
                var line = Console.ReadLine();
                var values = line.Split(' ').Select(v => int.Parse(v)).ToArray();
                g.AddEdge(values[0], values[1], values[2], values[3]);
            }
            Console.WriteLine($"{g.MinCostFlow(0, V-1, F)}");
        }
    }

    class PrimalDual
    {
        private int V;
        const int INF = 10000000;
        List<List<Edge>> Graph;
        int[] potential, minCost;
        int[] prevV, prevE;

        public PrimalDual(int V)
        {
            this.V = V;
            Graph = new List<List<Edge>>();
            for (int i = 0; i < V; i++)
            {
                Graph.Add(new List<Edge>());
            }
        }

        public void AddEdge(int from, int to, int cap, int cost)
        {
            // 順辺
            Graph[from].Add(new Edge
            {
                To = to,
                Cap = cap,
                Cost = cost,
                Rev = Graph[to].Count,
                IsRev = false
            });

            // 逆辺
            Graph[to].Add(new Edge
            {
                To = from,
                Cap = 0,
                Cost = -cost,
                Rev = (int) Graph[from].Count - 1,
                IsRev = true
            });
        }

        public int MinCostFlow(int s, int t, int f)
        {
            int ret = 0;

            // 初期化
            potential = new int[V];
            prevE = new int[V];
            prevV = new int[V];
            minCost = new int[V];

            for (int i = 0; i < V; i++)
            {
                potential[i] = 0;
                prevE[i] = -1;
                prevV[i] = -1;
                minCost[i] = 0;
            }

            // 流量を消費するまで
            while (f > 0)
            {
                // ダイクストラ
                var que = new PriorityQueue<Data>((d1, d2) => (d1.NextCost.CompareTo(d2.NextCost)));
                que.Push(new Data(0, s));
                for (int v = 0; v < V; v++)
                    minCost[v] = INF;
                minCost[s] = 0;

                while (que.Count() > 0)
                {
                    Data p = que.Pop();
                    if (minCost[p.To] < p.NextCost) continue; // 枝刈り
                    for (int i = 0; i < Graph[p.To].Count; i++)
                    {
                        Edge e = Graph[p.To][i];
                        int nextCost = minCost[p.To] + e.Cost + potential[p.To] - potential[e.To];
                        if (e.Cap > 0 && minCost[e.To] > nextCost)
                        {
                            prevE[e.To] = i;
                            prevV[e.To] = p.To;
                            minCost[e.To] = nextCost;
                            que.Push(new Data(minCost[e.To], e.To));
                        }
                    }
                }

                // 到達不可能
                if (minCost[t] == INF) return -1;

                // ポテンシャルの更新
                for (int v = 0; v < V; v++)
                    potential[v] += minCost[v];

                // 流せる流量
                int addflow = f;
                for (int v = t; v != s; v = prevV[v])
                {
                    addflow = Math.Min(addflow, Graph[prevV[v]][prevE[v]].Cap);
                }

                f -= addflow;

                // 費用の修正
                ret += addflow * potential[t];

                // 辺の更新
                for (int v = t; v != s; v = prevV[v])
                {
                    Edge e = Graph[prevV[v]][prevE[v]];
                    e.Cap -= addflow;
                    Graph[v][e.Rev].Cap += addflow;
                }
            }

            return ret;
        }

        void Output()
        {
            for (int i = 0; i < Graph.Count; i++)
            {
                foreach (var e in Graph[i])
                {
                    if (e.IsRev) continue;
                    var rev_e = Graph[e.To][e.Rev];
                    Console.WriteLine($"{i} -> {e.To} (flow: {rev_e.Cap} / {rev_e.Cap + e.Cap}");
                }
            }
        }
    }

    public class PriorityQueue<T>
    {
        private Comparison<T> _comparison;
        private int _type = 0;

        private T[] _heap;
        private int _sz = 0;

        private int _count = 0;

        /// <summary>
        /// Priority Queue with custom comparer
        /// </summary>
        public PriorityQueue(Comparison<T> comparison)
        {
            _heap = new T[128];
            _comparison = comparison;
        }

        private int Compare(T x, T y)
        {
            return _comparison(x, y);
        }

        public void Push(T x)
        {
            _count++;
            if (_count > _heap.Length)
            {
                var newheap = new T[_heap.Length * 2];
                for (int n = 0; n < _heap.Length; n++) newheap[n] = _heap[n];
                _heap = newheap;
            }

            //node number
            var i = _sz++;

            while (i > 0)
            {
                //parent node number
                var p = (i - 1) / 2;

                if (Compare(_heap[p], x) <= 0) break;

                _heap[i] = _heap[p];
                i = p;
            }

            _heap[i] = x;
        }

        public T Pop()
        {
            _count--;

            T ret = _heap[0];
            T x = _heap[--_sz];

            int i = 0;
            while (i * 2 + 1 < _sz)
            {
                //children
                int a = i * 2 + 1;
                int b = i * 2 + 2;

                if (b < _sz && Compare(_heap[b], _heap[a]) < 0) a = b;

                if (Compare(_heap[a], x) >= 0) break;

                _heap[i] = _heap[a];
                i = a;
            }

            _heap[i] = x;

            return ret;
        }

        public int Count()
        {
            return _count;
        }

        public T Peek()
        {
            return _heap[0];
        }

        public bool Contains(T x)
        {
            for (int i = 0; i < _sz; i++)
                if (x.Equals(_heap[i]))
                    return true;
            return false;
        }

        public void Clear()
        {
            while (this.Count() > 0) this.Pop();
        }

        public IEnumerator<T> GetEnumerator()
        {
            var ret = new List<T>();

            while (this.Count() > 0)
            {
                ret.Add(this.Pop());
            }

            foreach (var r in ret)
            {
                this.Push(r);
                yield return r;
            }
        }

        public T[] ToArray()
        {
            T[] array = new T[_sz];
            int i = 0;

            foreach (var r in this)
            {
                array[i++] = r;
            }

            return array;
        }
    }
}