[题解] CF1245D - Shichikuji and Power Grid

CF1245D - Shichikuji and Power Grid

题目传送门

题意

在一个网格图中,有 \(n\) 个城市。目标是使得 \(n\) 个城市都通电。

对于一个城市有电,要么选择在其位置建立发电站,要么和另一个有电的城市连线。

对于城市 \(i\) ,在其位置建立发电站的费用为 \(c_i\) ,和另一个城市 \(j\) 连电线的费用为 \((k_i + k_j) \times (\left| x_i - x_j \right| + \left| y_i - y_j \right|)\)

问使得所有城市都通电的情况下,如何得到费用最小的方案。

思路

可以发现,图中连线实际上就是图的边,考虑到 \(n\) 很小,可以直接建图。

现在考虑在哪里建电站比较好。我们可以假设只有一个额外地点建电站,那么在某个地方建电站,就转化为这个城市和这个额外地点连一条 \(c_i\) 边权的边,那么这个条件就转化完成了。

考虑如何使得代价最小。因为我们上面的操作,现在已经有了一张带权无向图了。我们要使得 \(n + 1\) 个点连通的费用最小,那么自然是最小生成树。因此,跑一遍最小生成树即可。

这里使用的是 Kruskal 算法,如果使用 Prime 实现,会更快一点。

实现

#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unused_imports)]

use std::fmt::write;
use std::io::{self, prelude::*, BufWriter};
use std::process::id;
use std::{str, vec};
use std::cmp::Ordering;

struct Scanner<R> {
    reader: R,
    buf_str: Vec<u8>,
    buf_iter: str::SplitAsciiWhitespace<'static>,
}
impl<R : io::BufRead> Scanner<R> {
    fn new(reader: R) -> Self {
        Self { reader, buf_str: Vec::new(), buf_iter: "".split_ascii_whitespace() }
    }
    fn next<T: str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buf_iter.next() {
                return token.parse().ok().expect("Failed parse");
            }
            self.buf_str.clear();
            self.reader.read_until(b'\n', &mut self.buf_str).expect("Failed read");
            self.buf_iter = unsafe {
                let slice = str::from_utf8_unchecked(&self.buf_str);
                std::mem::transmute(slice.split_ascii_whitespace())
            }
        }
    }
}

struct DisjointSet {
    leader : Vec<usize>
}
impl DisjointSet {
    fn new(n : usize) -> Self {
        let mut ret = Self {
            leader : vec![0; n]
        };
        for (i, v) in ret.leader.iter_mut().enumerate() {
            *v = i;
        }
        return ret;
    }
    fn get_leader(&mut self, x : usize) -> usize {
        if self.leader[x] == x {
            return x;
        } else {
            let ret = self.get_leader(self.leader[x]);
            self.leader[x] = ret;
            return ret;
        }
    }
    fn merge_to(&mut self, from : usize, to : usize) -> bool {
        let f = self.get_leader(from);
        let t = self.get_leader(to);
        if f == t {
            return false;
        }
        self.leader[f] = t;
        return true;
    }
    fn merge_to_max(&mut self, a : usize, b : usize) -> bool {
        let mut fa = self.get_leader(a);
        let mut fb = self.get_leader(b);
        if fa == fb {
            return false;
        } else if fa > fb {
            std::mem::swap(&mut fa, &mut fb);
        }
        self.leader[fa] = fb;
        return true;
    }
}

fn main() {
    let (stdin, stdout) = (io::stdin(), io::stdout());
    let mut scan = Scanner::new(stdin.lock());
    let mut out = std::io::BufWriter::new(stdout.lock());
    
    let n : usize = scan.next();

    let mut point : Vec<(i64, i64)> = vec![(0,0); n];
    for x in &mut point {
        x.0 = scan.next();
        x.1 = scan.next();    
    }
    let mut vc : Vec<u64> = vec![0; n];
    for x in &mut vc {
        *x = scan.next();
    }
    let mut vk : Vec<u64> = vec![0; n];
    for x in &mut vk {
        *x = scan.next();
    }

    let mut edge : Vec<(u32, u32, u64)> = Vec::with_capacity(n * n + n); 
    for (i, c) in vc.iter().enumerate() {
        edge.push((i as u32, n as u32, *c));
    }
    for (i, u) in point.iter().enumerate() {
        for (j, v) in point.iter().enumerate() {
            let x = u.0 - v.0;
            let y = u.1 - v.1;
            edge.push((i as u32, j as u32, (vk[i as usize] + vk[j as usize]) * ((x.abs() + y.abs()) as u64)));
        }
    }

    edge.sort_by(|&a, &b| a.2.cmp(&b.2));

    let mut dsu = DisjointSet::new(n + 1);
    let mut rete : Vec<(u32, u32)> = Vec::with_capacity(2 * n - 1);
    let mut retc : Vec<u32> = Vec::with_capacity(n);
    
    let mut cost : u64 = 0;
    
    for (u, v, w) in &edge {
        if dsu.merge_to(*u as usize, *v as usize) {
            cost += *w;
            if *v as usize >= n {
                retc.push(*u);
            } else {
                rete.push((*u, *v));
            }
        }
    }

    write!(out, "{}\n{}\n", cost, retc.len()).unwrap();
    for i in &retc {
        write!(out, "{} ", i + 1).unwrap();
    }
    write!(out, "\n{}\n", rete.len()).unwrap();
    for (u, v) in &rete {
        write!(out, "{} {}\n", u + 1, v + 1).unwrap();
    }
}
posted @ 2023-10-06 19:36  フランドール·スカーレット  阅读(51)  评论(0)    收藏  举报