#![allow(non_snake_case)] // todo: 近傍の種類を増やす fn main(){ get_time(); let mut scan=Scanner::new(); input!{ scan, n:usize, ab:[(i64,i64);n], } let pos=ab.into_iter().map(|t|P(t.0-MED,t.1-MED)).collect::>(); let mut log=[0.;65536]; for i in 0..65536{ log[i]=((i as f64+0.5)/65536.).ln(); } rnd::shuffle(&mut log); let mut state=State::new(&pos); anneal(&mut state,0.2,0.7,&log); // todo eprintln!("first_score = {:.2}",state.calc_score()); let mut tree=Tree::new(&pos,&state.ord); anneal(&mut tree,0.95,0.7,&log); // todo eprintln!("score = {:.2}",tree.calc_score()); let ans=tree.restore(); assert!(ans.len()==M); println!("\n{}",ans.len()); for &(u,v) in &ans{ println!("{} {}",u+1,v+1); } } #[derive(Clone)] struct State<'a>{ pos:&'a [P], ord:Vec, score:f64, } impl<'a> State<'a>{ fn new(pos:&'a [P])->Self{ let mut ret=Self{ pos, ord:(1..N).collect::>(), score:f64::INFINITY, }; ret.score=ret.calc_score(); ret } fn calc_score(&self)->f64{ let mut p=self.pos[0]; for &n in &self.ord{ p=p.merge(self.pos[n]); } (p.0.abs().max(p.1.abs()) as f64).ln() } } impl<'a> AnnealState for State<'a>{ fn score(&self)->f64{ self.score } fn trans(&mut self,add:f64)->bool{ // todo let i0=(0..3).map(|_|rnd::get(self.ord.len())).min().unwrap(); let i1=(0..3).map(|_|rnd::range_skip(0,self.ord.len(),i0)).min().unwrap(); self.ord.swap(i0,i1); let new=self.calc_score(); if add>=(new-self.score) as f64{ self.score=new; true } else{ self.ord.swap(i0,i1); false } } } const FIX:usize=25; // todo #[derive(Clone)] struct Tree{ fix:P, fix_ord:&'static [(usize,usize)], is:&'static [usize], pos:&'static [P], ord:Vec<(usize,usize)>, score:f64, } impl Tree{ fn new(pos:&[P],ans:&[usize])->Self{ let mut fix=P(0,0); let mut ord=vec![]; let mut is=vec![!0;N]; is[0]=0; let mut ps=vec![pos[0]]; let mut fix_ord=vec![]; for i in 0..ans.len(){ if ans.len()-i<=FIX{ fix=fix.merge(pos[ans[i]]); fix_ord.push((0,ans[i])); } else{ is[i+1]=ans[i]; ps.push(pos[ans[i]]); ord.push((0,i+1)); } } assert!(ps.len()==N-FIX); ord.splice(0..0,std::iter::repeat(ord[0]).take(M-FIX-ord.len())); assert!(ord.len()+FIX==M); let mut ret=Tree{ fix,ord, fix_ord:Box::leak(fix_ord.into_boxed_slice()), is:Box::leak(is.into_boxed_slice()), pos:Box::leak(ps.into_boxed_slice()), score:f64::INFINITY, }; ret.score=ret.calc_score(); ret } fn calc_score(&self)->f64{ let mut pos:[P;N-FIX]=self.pos.try_into().unwrap(); for &(u,v) in &self.ord{ pos[u]=pos[u].merge(pos[v]); pos[v]=pos[u]; } let i=(pos[0].0>>FIX)+self.fix.0; let j=(pos[0].1>>FIX)+self.fix.1; (i.abs().max(j.abs()) as f64).ln() } fn restore(&self)->Vec<(usize,usize)>{ self.ord.iter().map(|&t|(self.is[t.0],self.is[t.1])) .chain(self.fix_ord.iter().copied()) .collect() } } impl AnnealState for Tree{ fn score(&self)->f64{ self.score } fn trans(&mut self,add:f64)->bool{ let i=(0..3).map(|_|rnd::get(self.ord.len())).min().unwrap(); let u=if rnd::next()&1==0{ // todo 0 } else{ rnd::get(self.pos.len()) }; let v=rnd::range_skip(0,self.pos.len(),u); let old=self.ord[i]; if (u,v)==old || (v,u)==old{ return false; } self.ord[i]=(u,v); let new=self.calc_score(); if add>=(new-self.score) as f64{ self.score=new; true } else{ self.ord[i]=old; false } } } const N:usize=45; const M:usize=50; const MED:i64=5*1e17 as i64; #[derive(Clone,Copy)] struct P(i64,i64); impl P{ fn merge(self,a:Self)->Self{ P((self.0+a.0)/2,(self.1+a.1)/2) } } fn get_time()->f64{ static mut START:f64=0.; let time=std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs_f64(); unsafe{ if START==0.{ START=time; } #[cfg(local)]{ return (time-START)*1.; } time-START } } fn anneal(state:&mut S,tl:f64,init_heat:f64,log:&[f64]){ let start=get_time(); let tl=tl-start; assert!(0.state.score(){ stay=0; best=state.clone(); } else if stay>=1e5 as u64{ // todo stay=0; *state=best.clone(); } } *state=best; } trait AnnealState:Clone{ fn score(&self)->f64; fn trans(&mut self,add:f64)->bool; } #[allow(unused)] mod rnd { static mut A:u64=1; pub fn next()->u32{ unsafe{ let mut x=A; A*=0xcafef00dd15ea5e5; x^=x>>22; (x>>22+(x>>61)) as u32 } } pub fn nextf()->f64{ unsafe{ std::mem::transmute::(0x3ff0000000000000|(next() as u64)<<20)-1. } } pub fn get(n:usize)->usize{ assert!(n<=u32::MAX as usize); next() as usize*n>>32 } pub fn range(a:usize,b:usize)->usize{ assert!(ausize{ assert!(a<=skip && skip(list:&mut [T]){ for i in (0..list.len()).rev(){ list.swap(i,get(i+1)); } } } struct Scanner{ stack:std::str::SplitAsciiWhitespace<'static> } impl Scanner{ fn new()->Self{ use std::io::Read; let mut tmp=String::new(); std::io::stdin().read_to_string(&mut tmp).unwrap(); Self{stack:Box::leak(tmp.into_boxed_str()).split_ascii_whitespace()} } fn read(&mut self)->T{ self.stack.next().unwrap().parse::().unwrap_or_else(|_|panic!("parse error {}",std::any::type_name::())) } } #[macro_export] macro_rules! input{ ($scan:expr $(,)?)=>{}; ($scan:expr, $name:ident:$t:tt $($rest:tt)*)=>{ let $name=read_value!($scan,$t); input!{$scan $($rest)*} }; } #[macro_export] macro_rules! read_value{ ($scan:expr, ($($t:tt),*))=>{ ($(read_value!($scan, $t)),*) }; ($scan:expr, [$t:tt;$len:expr])=>{ (0..$len).map(|_|read_value!($scan,$t)).collect::>() }; ($scan:expr, $t:ty)=>{ $scan.read::<$t>() }; }