Cod sursa(job #3281634)

Utilizator freak93Adrian Budau freak93 Data 3 martie 2025 00:13:27
Problema Cuplaj maxim de cost minim Scor 70
Compilator rs Status done
Runda Arhiva educationala Marime 9.34 kb
pub(crate) use __cargo_equip::prelude::*;

use std::{
    fs::File,
    ops::{Deref, DerefMut},
};

use competitive::prelude::*;

const INF: i64 = i64::MAX / 2;

struct Assignment {
    cost: Vec<Vec<i64>>,
}

impl Assignment {
    fn new(n: usize, m: usize) -> Self {
        Self {
            cost: mat![n; m; INF / (n + m) as i64],
        }
    }

    fn min_assignment(&self, n: usize) -> Vec<Option<usize>> {
        let m = self.cost[0].len();
        let mut dist = vec![0; m];
        let mut potential = vec![0; m];
        let mut l: Vec<Option<usize>> = vec![None; n];
        let mut r: Vec<Option<usize>> = vec![None; m];
        let mut from = vec![0; m];
        let mut used = vec![false; m];

        for i in 0..n {
            for j in 0..m {
                dist[j] = self.cost[i][j] - potential[j];
                from[j] = i;
                used[j] = false;
            }

            let (to, w) = 'path: loop {
                let w = (0..m)
                    .filter_map(|j| if !used[j] { Some(dist[j]) } else { None })
                    .min()
                    .unwrap();

                for j in 0..m {
                    if used[j] || dist[j] != w {
                        continue;
                    }
                    let Some(k) = r[j] else {
                        break 'path (j, w);
                    };
                    used[j] = true;
                    for jj in 0..m {
                        if used[jj] {
                            continue;
                        }
                        let tmp =
                            self.cost[k][jj] - potential[jj] - self.cost[k][j] + potential[j] + w;
                        if tmp > dist[jj] {
                            continue;
                        }
                        dist[jj] = tmp;
                        from[jj] = k;
                    }
                }
            };

            for j in 0..m {
                if !used[j] {
                    continue;
                }
                potential[j] += dist[j] - w;
            }

            let mut to = Some(to);
            while let Some(y) = to {
                let x = from[y];
                r[y] = Some(x);
                swap!(to, l[x]);
            }
        }
        l
    }
}

impl Deref for Assignment {
    type Target = [Vec<i64>];

    fn deref(&self) -> &Self::Target {
        &self.cost
    }
}

impl DerefMut for Assignment {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.cost
    }
}

fn main() -> Result {
    let input = &mut Scanner::new(File::open("cmcm.in")?);
    let output = &mut Printer::new(File::create("cmcm.out")?);

    let n = input.read()?;
    let m = input.read()?;
    let e = input.read()?;

    let mut ass = Assignment::new(n, m);
    let mut index = mat![n; m; None];
    for i in 0..e {
        let p: usize = input.read()?;
        let q: usize = input.read()?;
        let c = input.read()?;
        ass[p - 1][q - 1] = c;
        index[p - 1][q - 1] = Some(i);
    }

    let l = ass.min_assignment(n);

    let mut answer = Vec::new();
    let mut cost = 0;
    for i in 0..n {
        let Some(j) = l[i] else {
            continue;
        };
        let Some(idx) = index[i][j] else {
            continue;
        };
        answer.push(idx);
        cost += ass[i][j];
    }

    writeln!(output, "{} {}", answer.len(), cost)?;
    for i in answer {
        write!(output, "{} ", i + 1)?;
    }
    writeln!(output)?;

    Ok(())
}

// The following code was expanded by `cargo-equip`.

///  # Bundled libraries
/// 
///  - `path+file:///Users/adrian/work/rust/competitive#0.1.0` published in **missing** licensed under `MIT` as `crate::__cargo_equip::crates::competitive`
/// 
///  # License and Copyright Notices
/// 
///  - `path+file:///Users/adrian/work/rust/competitive#0.1.0`
/// 
///      ```text
///      MIT License
/// 
///      Copyright (c) 2024 Adrian Budau
/// 
///      Permission is hereby granted, free of charge, to any person obtaining a copy
///      of this software and associated documentation files (the "Software"), to deal
///      in the Software without restriction, including without limitation the rights
///      to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
///      copies of the Software, and to permit persons to whom the Software is
///      furnished to do so, subject to the following conditions:
/// 
///      The above copyright notice and this permission notice shall be included in all
///      copies or substantial portions of the Software.
/// 
///      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
///      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
///      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
///      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
///      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
///      OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
///      SOFTWARE.
/// 
///      ```
#[cfg_attr(any(), rustfmt::skip)]
#[allow(unused)]
mod __cargo_equip {
    pub(crate) mod crates {
        pub(crate) mod competitive {pub(crate)use crate::__cargo_equip::macros::competitive::*;pub(crate)mod result{pub(crate)type Result<T=()> =std::result::Result<T,Box<dyn std::error::Error>>;}pub(crate)mod iter{use std::mem;pub(crate)fn partition<'a,T:'a>(mut iter:impl DoubleEndedIterator<Item=&'a mut T>,mut predicate:impl FnMut(&T)->bool,)->usize{let mut count=0;while let Some(head)=iter.find(|elem|{let p=predicate(*elem);count+=p as usize;!p}){let Some(tail)=iter.rfind(|elem|predicate(*elem))else{break;};mem::swap(head,tail);count+=1;}count}pub(crate)fn next_permutation<T:Ord>(slice:&mut[T])->bool{if slice.is_empty(){return false;}let n=slice.len();let mut i=n-1;while i>0&&slice[i-1]>=slice[i]{i-=1;}if i==0{slice.reverse();return false;}let pos=slice.iter().enumerate().rfind(|(_,v)|**v>slice[i-1]).unwrap().0;slice.swap(i-1,pos);slice[i..].reverse();true}pub(crate)trait IteratorExt:Iterator+Sized{fn try_collect_vec<T,E>(self)->Result<Vec<T>,E>where Self:Iterator<Item=Result<T,E>>,{self.collect()}}impl<I:Iterator>IteratorExt for I{}}pub(crate)mod printer{use std::io::{self,BufWriter,IsTerminal,StdoutLock,Write};pub(crate)enum Printer<W:Write=StdoutLock<'static>>{Buffered(BufWriter<W>),Unbuffered(W),}impl<W:Write>Printer<W>{pub(crate)fn new(writer:W)->Self where W:IsTerminal,{if writer.is_terminal(){Self::Unbuffered(writer)}else{Self::Buffered(BufWriter::new(writer))}}}impl Printer<StdoutLock<'static>>{pub(crate)fn stdout()->Self{Self::new(io::stdout().lock())}}impl<W:Write>Write for Printer<W>{fn write(&mut self,buf:&[u8])->io::Result<usize>{match self{Printer::Buffered(w)=>w.write(buf),Printer::Unbuffered(w)=>w.write(buf),}}fn flush(&mut self)->io::Result<()>{match self{Printer::Buffered(w)=>w.flush(),Printer::Unbuffered(w)=>w.flush(),}}}}pub(crate)mod scanner{use super::result::Result;use std::{collections::VecDeque,io::{self,BufRead,BufReader,Read,StdinLock},str::FromStr,};pub(crate)struct Scanner<R:Read=StdinLock<'static>>{reader:BufReader<R>,tokens:VecDeque<String>,}impl<R:Read>Scanner<R>{pub(crate)fn new(reader:R)->Self{Self{reader:BufReader::new(reader),tokens:VecDeque::new(),}}pub(crate)fn next(&mut self)->io::Result<String>{if let Some(token)=self.tokens.pop_front(){return Ok(token);};let mut line=String::new();self.reader.read_line(&mut line)?;if line.is_empty(){return Err(io::ErrorKind::UnexpectedEof.into());}self.tokens=line.split_ascii_whitespace().map(str::to_owned).collect();self.next()}pub(crate)fn read<T:FromStr>(&mut self)->Result<T>where T::Err:std::error::Error+'static,{let token=self.next()?;Ok(token.parse()?)}}impl Scanner{pub(crate)fn stdin()->Self{Self::new(io::stdin().lock())}}pub(crate)trait Scannable<R:Read=StdinLock<'static>>:Sized{fn read(scanner:&mut Scanner<R>)->Result<Self>;}macro_rules!impl_tuple{($($t:tt),+)=>{impl<R:Read,$($t,)+>Scannable<R>for($($t,)+)where$($t:FromStr,$t::Err:std::error::Error+'static,)+{fn read(scanner:&mut Scanner<R>)->Result<Self>{Ok(($(scanner.read::<$t>()?,)+))}}}}impl_tuple!(T0);impl_tuple!(T0,T1);impl_tuple!(T0,T1,T2);impl_tuple!(T0,T1,T2,T3);impl_tuple!(T0,T1,T2,T3,T4);impl_tuple!(T0,T1,T2,T3,T4,T5);impl_tuple!(T0,T1,T2,T3,T4,T5,T6);impl_tuple!(T0,T1,T2,T3,T4,T5,T6,T7);impl_tuple!(T0,T1,T2,T3,T4,T5,T6,T7,T8);}pub(crate)mod prelude{pub(crate)use super::iter::{next_permutation,partition,IteratorExt};pub(crate)use super::printer::Printer;pub(crate)use super::result::Result;pub(crate)use super::scanner::{Scannable,Scanner};pub(crate)use std::io::Write;#[macro_export]macro_rules!__cargo_equip_macro_def_competitive_swap{($a:expr,$b:expr)=>{std::mem::swap(&mut$a,&mut$b);};}macro_rules!swap{($($tt:tt)*)=>(crate::__cargo_equip_macro_def_competitive_swap!{$($tt)*})}pub(crate)use swap;#[macro_export]macro_rules!__cargo_equip_macro_def_competitive_mat{($dim:expr;$value:expr)=>{vec![$value;$dim]};($dim:expr;$($rest:expr);*)=>{vec![mat!($($rest);*);$dim]};}macro_rules!mat{($($tt:tt)*)=>(crate::__cargo_equip_macro_def_competitive_mat!{$($tt)*})}pub(crate)use mat;}}
    }

    pub(crate) mod macros {
        pub(crate) mod competitive {pub(crate)use crate::{__cargo_equip_macro_def_competitive_mat as mat,__cargo_equip_macro_def_competitive_swap as swap};}
    }

    pub(crate) mod prelude {pub(crate) use crate::__cargo_equip::crates::*;}

    mod preludes {
        pub(crate) mod competitive {}
    }
}