[题解] CF1245D - Shichikuji and Power Grid

CF1245D - Shichikuji and Power Grid

题目传送门

题意

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

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

对于城市 i ,在其位置建立发电站的费用为 ci ,和另一个城市 j 连电线的费用为 (ki+kj)×(|xixj|+|yiyj|)

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

思路

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

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

考虑如何使得代价最小。因为我们上面的操作,现在已经有了一张带权无向图了。我们要使得 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 @   フランドール·スカーレット  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示