A flow network is a directed graph which has a $source$ and a $sink$. In a flow network, each edge $(u, v)$ has a capacity $c(u, v)$. Each edge receives a flow, but the amount of flow on the edge can not exceed the corresponding capacity. Find the maximum flow from the $source$ to the $sink$.

Constraints

* $2 \leq |V| \leq 100$
* $1 \leq |E| \leq 1000$
* $0 \leq c_i \leq 10000$

Input

A flow network is given in the following format.

$|V|\;|E|$
$u_0\;v_0\;c_0$
$u_1\;v_1\;c_1$
:
$u_{|E|-1}\;v_{|E|-1}\;c_{|E|-1}$



$|V|$, $|E|$ is the number of vertices and edges 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$ 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$ is the capacity of $i$-th edge.

Output

Print the maximum flow.

Example

Input

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


Output

3
import java.io.*;
import java.util.*;

public class Main implements Runnable{
    private ArrayList<ArrayList<Integer>> graph;
    private Edge[] edges;
    public static void main(String[] args) throws Exception {
        new Thread(null, new Main(), "bridge", 16 * 1024 * 1024).start();
    }

    @Override
    public void run() {
        try {
            solve();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void solve() throws Exception{
        FastScanner scanner = new FastScanner(System.in);

        int V = scanner.nextInt();
        int E = scanner.nextInt();

        graph = new ArrayList<>(V);
        edges = new Edge[E * 2];

        for(int i = 0; i < V; ++i){
            graph.add(new ArrayList<Integer>());
        }

        int edgeSize = 0;
        for(int i = 0; i < E; ++i){
            int u = scanner.nextInt();
            int v = scanner.nextInt();
            int c = scanner.nextInt();

            edges[edgeSize++] = new Edge(u, v, 0, c);
            edges[edgeSize++] = new Edge(v, u, 0, 0);

            graph.get(u).add(edgeSize - 2);
            graph.get(v).add(edgeSize - 1);
        }

        System.out.println(maxFlow(0, V - 1));
    }

    private int maxFlow(int s, int t){
        int V = graph.size();
        int[] dist = new int[V];
        int totalFlow = 0;
        while(dinicBFS(s, t, dist)){
            int flow;
            int[] index = new int[V];
            while((flow = dinicDFS(s, t, dist, index, Integer.MAX_VALUE)) > 0){
                totalFlow += flow;
            }
        }

        return totalFlow;
    }

    private boolean dinicBFS(int s, int t, int[] dist){
        Arrays.fill(dist, -1);
        dist[s] = 0;

        LinkedList<Integer> queue = new LinkedList<>();
        queue.offer(s);

        while(!queue.isEmpty()){
            int u = queue.poll();

            for(int edgeIndex : graph.get(u)){
                Edge edge = edges[edgeIndex];
                if(dist[edge.v] == -1 && edge.flow < edge.cap){
                    queue.offer(edge.v);
                    dist[edge.v] = dist[edge.u] + 1;
                }
            }
        }

        return dist[t] != -1;
    }

    private int dinicDFS(int u, int t, int[] dist, int[] index, int flow){
        if(u == t){
            return flow;
        }

        for(; index[u] < graph.get(u).size(); ++index[u]){
            int edgeIndex = graph.get(u).get(index[u]);
            Edge edge = edges[edgeIndex];
            if(dist[edge.v] == dist[edge.u] + 1 && edge.flow < edge.cap){
                int pathFlow = dinicDFS(edge.v, t, dist, index, Math.min(flow, edge.cap - edge.flow));
                if(pathFlow > 0){
                    edge.flow += pathFlow;
                    edges[edgeIndex ^ 1].flow -= pathFlow;
                    return pathFlow;
                }
            }
        }

        return 0;
    }

    static class Edge{
        int u;
        int v;
        int flow;
        int cap;

        public Edge(int u, int v, int flow, int cap){
            this.u = u;
            this.v = v;
            this.flow = flow;
            this.cap = cap;
        }
    }

    static class FastScanner {
        private InputStream in;
        private final byte[] buffer = new byte[1024 * 8];
        private int ptr = 0;
        private int buflen = 0;

        public FastScanner(InputStream in){
            this.in = in;
        }

        private boolean hasNextByte() {
            if (ptr < buflen) {
                return true;
            } else {
                ptr = 0;
                try {
                    buflen = in.read(buffer);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (buflen <= 0) {
                    return false;
                }
            }
            return true;
        }

        private int readByte() {
            if (hasNextByte()) return buffer[ptr++];
            else return -1;
        }

        private static boolean isPrintableChar(int c) {
            return 33 <= c && c <= 126;
        }

        private void skipUnprintable() {
            while (hasNextByte() && !isPrintableChar(buffer[ptr])) ptr++;
        }

        public boolean hasNext() {
            skipUnprintable();
            return hasNextByte();
        }

        public String next() {
            if (!hasNext()) throw new NoSuchElementException();
            StringBuilder sb = new StringBuilder();
            int b = readByte();
            while (isPrintableChar(b)) {
                sb.appendCodePoint(b);
                b = readByte();
            }
            return sb.toString();
        }

        public long nextLong() {
            return Long.parseLong(next());
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

        public double nextDouble() {
            return Double.parseDouble(next());
        }
    }
}