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 {}
}
}