macro_rules ! input { ( source = $ s : expr , $ ( $ r : tt ) * ) => { let mut iter = $ s . split_whitespace ( ) ; input_inner ! { iter , $ ( $ r ) * } } ; ( iter = $ iter : ident , $ ( $ r : tt ) * ) => { let s = { use std :: io :: Read ; let mut s = String :: new ( ) ; std :: io :: stdin ( ) . read_to_string ( & mut s ) . unwrap ( ) ; s } ; let mut $ iter = s . split_whitespace ( ) ; input_inner ! { $ iter , $ ( $ r ) * } } ; ( $ ( $ r : tt ) * ) => { let s = { use std :: io :: Read ; let mut s = String :: new ( ) ; std :: io :: stdin ( ) . read_to_string ( & mut s ) . unwrap ( ) ; s } ; let mut iter = s . split_whitespace ( ) ; input_inner ! { iter , $ ( $ r ) * } } ; }
macro_rules ! input_inner { ( $ iter : expr ) => { } ; ( $ iter : expr , ) => { } ; ( $ iter : expr , mut $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let mut $ var = read_value ! ( $ iter , $ t ) ; input_inner ! { $ iter $ ( $ r ) * } } ; ( $ iter : expr , mut $ var : ident $ ( $ r : tt ) * ) => { input_inner ! { $ iter , mut $ var : usize $ ( $ r ) * } } ; ( $ iter : expr , $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let $ var = read_value ! ( $ iter , $ t ) ; input_inner ! { $ iter $ ( $ r ) * } } ; ( $ iter : expr , $ var : ident $ ( $ r : tt ) * ) => { input_inner ! { $ iter , $ var : usize $ ( $ r ) * } } ; }
macro_rules ! read_value { ( $ iter : expr , ( $ ( $ t : tt ) ,* ) ) => { ( $ ( read_value ! ( $ iter , $ t ) ) ,* ) } ; ( $ iter : expr , [ $ t : tt ; $ len : expr ] ) => { ( 0 ..$ len ) . map ( | _ | read_value ! ( $ iter , $ t ) ) . collect ::< Vec < _ >> ( ) } ; ( $ iter : expr , { chars : $ base : expr } ) => { read_value ! ( $ iter , String ) . chars ( ) . map ( | c | ( c as u8 - $ base as u8 ) as usize ) . collect ::< Vec < usize >> ( ) } ; ( $ iter : expr , { char : $ base : expr } ) => { read_value ! ( $ iter , { chars : $ base } ) [ 0 ] } ; ( $ iter : expr , chars ) => { read_value ! ( $ iter , String ) . chars ( ) . collect ::< Vec < char >> ( ) } ; ( $ iter : expr , char ) => { read_value ! ( $ iter , chars ) [ 0 ] } ; ( $ iter : expr , usize1 ) => { read_value ! ( $ iter , usize ) - 1 } ; ( $ iter : expr , $ t : ty ) => { $ iter . next ( ) . unwrap ( ) . parse ::<$ t > ( ) . unwrap ( ) } ; }
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Rev<T>(pub T);
impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<std::cmp::Ordering> {
        other.0.partial_cmp(&self.0)
    }
}
impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> std::cmp::Ordering {
        other.0.cmp(&self.0)
    }
}
#[derive(Debug, Clone)]
pub struct RevEdge {
    pub to: usize,
    pub rev: usize,
    pub cap: u64,
    pub cost: i64,
}
impl RevEdge {
    pub fn new(to: usize, rev: usize, cap: u64, cost: i64) -> RevEdge {
        RevEdge {
            to: to,
            rev: rev,
            cap: cap,
            cost: cost,
        }
    }
}
#[derive(Debug)]
pub struct PrimalDual {
    n: usize,
    graph: Vec<Vec<RevEdge>>,
    potential: Vec<i64>,
    cost: Vec<i64>,
    prev_vertex: Vec<usize>,
    prev_edge: Vec<usize>,
}
impl PrimalDual {
    pub fn new(n: usize) -> PrimalDual {
        PrimalDual {
            n: n,
            graph: vec![vec![]; n],
            potential: vec![],
            cost: vec![],
            prev_vertex: vec![],
            prev_edge: vec![],
        }
    }
    pub fn add_edge(&mut self, from: usize, to: usize, cap: u64, cost: i64) {
        let e1 = RevEdge::new(to, self.graph[to].len(), cap, cost);
        let e2 = RevEdge::new(from, self.graph[from].len(), 0, -cost);
        self.graph[from].push(e1);
        self.graph[to].push(e2);
    }
    pub fn minimum_cost_flow(&mut self, s: usize, t: usize, f: u64) -> Option<i64> {
        use std::cmp::min;
        self.potential = vec![0; self.n];
        self.prev_edge = vec![0; self.n];
        self.prev_vertex = vec![0; self.n];
        let mut res = 0;
        let mut f = f;
        while f > 0 {
            self.dijkstra(s);
            if self.cost[t] == std::i64::MAX {
                return None;
            }
            for v in 0..self.n {
                self.potential[v] += self.cost[v];
            }
            let mut add_f = f;
            let mut v = t;
            while v != s {
                add_f = min(
                    add_f,
                    self.graph[self.prev_vertex[v]][self.prev_edge[v]].cap,
                );
                v = self.prev_vertex[v];
            }
            f -= add_f;
            res += add_f as i64 * self.potential[t];
            let mut v = t;
            while v != s {
                self.graph[self.prev_vertex[v]][self.prev_edge[v]].cap -= add_f;
                let r = self.graph[self.prev_vertex[v]][self.prev_edge[v]].rev;
                self.graph[v][r].cap += add_f;
                v = self.prev_vertex[v];
            }
        }
        Some(res)
    }
    fn dijkstra(&mut self, s: usize) {
        use std::collections::BinaryHeap;
        self.cost = vec![std::i64::MAX; self.n];
        let mut heap = BinaryHeap::new();
        self.cost[s] = 0;
        heap.push((Rev(0), s));
        while let Some((d, u)) = heap.pop() {
            let d = d.0;
            for i in 0..self.graph[u].len() {
                let e = &self.graph[u][i];
                let ncost = self.cost[u] + e.cost + self.potential[u] - self.potential[e.to];
                if e.cap > 0 && self.cost[e.to] > ncost {
                    self.cost[e.to] = ncost;
                    self.prev_vertex[e.to] = u;
                    self.prev_edge[e.to] = i;
                    heap.push((Rev(d + e.cost), e.to));
                }
            }
        }
    }
}
fn main() {
    input! { n, m, f: u64, uvcd: [(usize, usize, u64, i64); m] };
    let mut mcf = PrimalDual::new(n);
    for &(u, v, c, d) in &uvcd {
        mcf.add_edge(u, v, c, d);
    }
    println!("{}", mcf.minimum_cost_flow(0, n - 1, f).unwrap_or(-1));
}



Measured memory_bytes: 5052