https://atcoder.jp/contests/abc396/tasks/abc396_e
ノードXとYを重みWで結ぶ無向グラフと考えます。
入力例1では、A1=vとすると、グラフを辿って、A2=v XOR 3、A3=v XOR 4となります。なので、
(v XOR 0) + (v XOR 3) + (v XOR 4)
を最小化するvを求めればよいです。
XORなので各ビットで考えればよいです。0, 3, 4を2進数にすると、
000 011 100
一番右のビットは010なので、vの一番下のビットを0とするとXORを取ると010、1とすると101になって、0を取る方が和が小さいことが分かります。要するに各ビットで考えて、0が多ければ0、1が多ければ1とすればよいです。
// Minimum XOR Path #![allow(non_snake_case)] //////////////////// library //////////////////// fn read<T: std::str::FromStr>() -> T { let mut line = String::new(); std::io::stdin().read_line(&mut line).ok(); line.trim().parse().ok().unwrap() } fn read_vec<T: std::str::FromStr>() -> Vec<T> { read::<String>().split_whitespace() .map(|e| e.parse().ok().unwrap()).collect() } //////////////////// UnionFind //////////////////// use std::cmp::max; type Node = usize; struct UnionFind { parents: Vec<Node>, heights: Vec<i32>, } impl UnionFind { fn new(N: usize) -> UnionFind { let parents: Vec<Node> = (0..N).collect(); let heights: Vec<i32> = vec![1; N]; UnionFind { parents, heights } } fn is_root(&self, v: Node) -> bool { self.parents[v] == v } fn join(&mut self, u: Node, v: Node) { let r1 = self.root(u); let r2 = self.root(v); if r1 == r2 { return // ここには来ないはず } let h1 = self.heights[r1]; let h2 = self.heights[r2]; if h1 <= h2 { // r2にr1がぶら下がる self.parents[r1] = r2; self.heights[r2] = max(self.heights[r2], self.heights[r1]+1); } else { self.parents[r2] = r1; self.heights[r1] = max(self.heights[r1], self.heights[r2]+1); } } fn root(&self, v0: Node) -> Node { if self.is_root(v0) { v0 } else { let p = self.parents[v0]; self.root(p) } } } //////////////////// Graph //////////////////// use std::collections::HashMap; type Weight = i64; type Edge = (Node, Node, Weight); fn read_edge() -> Edge { let v: Vec<usize> = read_vec(); (v[0]-1, v[1]-1, v[2] as Weight) } struct Graph { g: HashMap<Node, Vec<(Node, Weight)>> } impl Graph { fn len(&self) -> usize { self.g.len() } fn neighbors(&self, v: Node) -> Vec<(Node, Weight)> { if let Some(ref neighs) = self.g.get(&v) { neighs.to_vec() } else { vec![] } } fn divide_into_connected(&self) -> Vec<Graph> { let mut uf = UnionFind::new(self.len()); for (&u, &ref vs) in self.g.iter() { for &(v, _w) in vs.iter() { uf.join(u, v) } } let mut m: HashMap<Node, Vec<Node>> = HashMap::new(); for (&v, _) in self.g.iter() { let r = uf.root(v); let e = m.entry(r).or_insert(vec![]); (*e).push(v) } let mut gs: Vec<Graph> = vec![]; for (_, vs) in m.into_iter() { let g = vs.into_iter(). map(|v| (v, self.g.get(&v).unwrap().to_vec())). collect::<HashMap<_, _>>(); gs.push(Graph { g }) } gs } fn create(N: usize, edges: Vec<Edge>) -> Graph { let mut g: HashMap<Node, Vec<(Node, Weight)>> = (0..N).map(|v| (v, vec![])).collect(); for (u, v, w) in edges.into_iter() { let e1 = g.entry(u).or_insert(vec![]); (*e1).push((v, w)); let e2 = g.entry(v).or_insert(vec![]); (*e2).push((u, w)) } Graph { g } } } //////////////////// process //////////////////// fn read_input() -> (usize, Vec<Edge>) { let v: Vec<usize> = read_vec(); let (N, M) = (v[0], v[1]); let edges: Vec<Edge> = (0..M).map(|_| read_edge()).collect(); (N, edges) } fn remove_duplicated_edges(edges: Vec<Edge>) -> Vec<Edge> { let mut dic: HashMap<(Node, Node), Weight> = HashMap::new(); for (u, v, w) in edges { let uv = if u < v { (u, v) } else { (v, u) }; if let Some(&w1) = dic.get(&uv) { if w1 != w { return vec![] } } else { dic.insert(uv, w); } } dic.into_iter().map(|((u, v), w)| (u, v, w)).collect::<Vec<Edge>>() } fn walk(v0: Node, graph: &Graph, A: &mut Vec<Weight>) -> bool { let neighs = graph.neighbors(v0); for (v, w) in neighs { if A[v] == -1 { A[v] = A[v0] ^ w; if !walk(v, &graph, A) { return false } } else if A[v] != A[v0] ^ w { return false } } true } fn num_bits(a: &Vec<Weight>) -> u64 { let max_a: Weight = *a.iter().max().unwrap(); let mut n: u64 = 0; while (1 << n) <= max_a { n += 1 } n } fn minimize(graph: Graph, A: &mut Vec<Weight>) { let a: Vec<Weight> = graph.g.keys().map(|&v| A[v]).collect(); let mut s: i64 = 0; let L = graph.g.len() as i64; for i in 0..num_bits(&a) { let num_ones = a.iter().map(|&e| (e >> i) & 1).sum::<i64>(); if num_ones * 2 > L { s |= 1 << i } } for &v in graph.g.keys() { A[v] ^= s } } fn F_each(graph: Graph, A: &mut Vec<Weight>) -> bool { let v0 = *graph.g.keys().next().unwrap(); A[v0] = 0; let b = walk(v0, &graph, A); if b { minimize(graph, A) } b } fn F(N: usize, edges: Vec<Edge>) -> Vec<Weight> { if edges.is_empty() { return vec![0; N] } let filtered_edges = remove_duplicated_edges(edges); if filtered_edges.is_empty() { return vec![] } let graph = Graph::create(N, filtered_edges); let subgraphs = graph.divide_into_connected(); let mut A: Vec<Weight> = vec![-1; N]; for subg in subgraphs { if !F_each(subg, &mut A) { return vec![] } } A } fn main() { let (N, edges) = read_input(); let A = F(N, edges); if A.is_empty() { println!("-1") } else { let s = A.into_iter().map(|a| a.to_string()). collect::<Vec<String>>().join(" "); println!("{}", s) } }