2023-08-04: 村には n 軒の家があります
井戸を建設し、パイプを敷設して、すべての家に水を供給したいと考えています。
各家 i には、2 つの代替給水計画があります。
一つは、家の中に直接井戸を建てる方法です。
コストは Wells[i - 1] (インデックスは 0 から始まるため、-1 に注意してください)
もう一つは、別の井戸から水をパイプで引くことです。
アレイパイプは家と家の間にパイプを敷設するコストを提供します
ここで、各パイプ[j] = [house1j, house2j,costj]
house1j と house2j を一緒に配管するコストを表します。接続は双方向です。
すべての住宅に水を提供するための最低の総コストを返します。
この質問は非常に頻繁にあり、注目を集めていますが、
それ自体は難しいことではなく、最小スパニングツリー問題に変換するだけです。
入力: n = 3、井戸 = [1,2,2]、パイプ = [[1,2,1],[2,3,1]]。
出力: 3。
小紅書とバイトダンスから。
2023 年 8 月 4 日の回答:
一般的なプロセスは次のとおりです。
1. 初期化:
1.1. パイプライン情報を保存するエッジ配列エッジを作成します。
1.2. 各ハウス i を独立した連結成分として扱い、親配列 Father[i] を i に初期化します。
1.3. 各ハウスのサイズ配列 size[i] を作成し、1 に初期化します。
1.4. パス圧縮用の補助配列ヘルプを作成します。
2. エッジ配列を構築します。
2.1. 各家 i に井戸を建設するコストである Wells[i-1] をエッジ配列のエッジに追加します。
2.2. 各パイプラインの情報[house1j、house2j、costj]をエッジ配列edgeに追加します。
3. エッジ配列をソートします。
3.1. エッジのコストに従って、エッジ配列のエッジを小さいものから大きいものまで並べ替えます。
4. ビルドして確認します。
4.1. build(n) 関数を呼び出して初期化および検索します。
5. 最小スパニングツリーの構築と最小総コストの計算:
5.1. ans = 0 を初期化して、最小総コストを記録します。
5.2. エッジ配列のエッジをトラバースし、各エッジedges[i]に対して次の手順を実行します。
5.2.1.edges[i] の 2 つのノードが接続されているかどうかを判断します (結合で find() 関数を使用します)。
5.2.1.1. 接続されていない場合は、2 つのノードを結合します (結合検索セットの Union() 関数を使用します)。
5.2.1.2. 同時に、このエッジのコストedges[i][2]を総コストansに加算します。
6. 最小総コストを返します。
合計時間計算量: O((n+m)log(n+m))。エッジ配列がソートされているため、n は住宅の数、m はパイプの数です。
空間の総複雑さ: O(n+m)。ここで、n は家の数、m はパイプの数 (エッジの数) です。
go の完全なコードは次のとおりです。
package main
import (
"fmt"
"sort"
)
const MAXN = 10010
var edges [][3]int
var esize int
var father [MAXN]int
var size [MAXN]int
var help [MAXN]int
func build(n int) {
for i := 0; i <= n; i++ {
father[i] = i
size[i] = 1
}
}
func find(i int) int {
s := 0
for i != father[i] {
help[s] = i
i = father[i]
s++
}
for s > 0 {
s--
father[help[s]] = i
}
return i
}
func union(i, j int) bool {
f1 := find(i)
f2 := find(j)
if f1 != f2 {
if size[f1] >= size[f2] {
father[f2] = f1
size[f1] += size[f2]
} else {
father[f1] = f2
size[f2] += size[f1]
}
return true
}
return false
}
func minCostToSupplyWater(n int, wells []int, pipes [][]int) int {
esize = 0
for i := 0; i < n; i++ {
edges = append(edges, [3]int{
0, i + 1, wells[i]})
esize++
}
for i := 0; i < len(pipes); i++ {
edges = append(edges, [3]int{
pipes[i][0], pipes[i][1], pipes[i][2]})
esize++
}
sort.Slice(edges, func(i, j int) bool {
return edges[i][2] < edges[j][2]
})
build(n)
ans := 0
for i := 0; i < esize; i++ {
if union(edges[i][0], edges[i][1]) {
ans += edges[i][2]
}
}
return ans
}
func main() {
n := 3
wells := []int{
1, 2, 2}
pipes := [][]int{
{
1, 2, 1}, {
2, 3, 1}}
result := minCostToSupplyWater(n, wells, pipes)
fmt.Println(result)
}
Rustのコードは次のとおりです。
const MAXN: i32 = 10010;
static mut EDGES: [[i32; 3]; (MAXN << 1) as usize] = [[0; 3]; (MAXN << 1) as usize];
static mut ESIZE: i32 = 0;
static mut FATHER: [i32; MAXN as usize] = [0; MAXN as usize];
static mut SIZE: [i32; MAXN as usize] = [0; MAXN as usize];
static mut HELP: [i32; MAXN as usize] = [0; MAXN as usize];
fn build(n: i32) {
for i in 0..=n {
unsafe {
FATHER[i as usize] = i;
SIZE[i as usize] = 1;
}
}
}
fn find(i: i32) -> i32 {
let mut s = 0;
unsafe {
let mut index = i;
while index != FATHER[index as usize] {
HELP[s] = index;
index = FATHER[index as usize];
s += 1;
}
while s > 0 {
s -= 1;
FATHER[HELP[s] as usize] = index;
}
return index;
}
}
fn union(i: i32, j: i32) -> bool {
let f1 = find(i);
let f2 = find(j);
unsafe {
if f1 != f2 {
if SIZE[f1 as usize] >= SIZE[f2 as usize] {
FATHER[f2 as usize] = f1;
SIZE[f1 as usize] += SIZE[f2 as usize];
} else {
FATHER[f1 as usize] = f2;
SIZE[f2 as usize] += SIZE[f1 as usize];
}
return true;
} else {
return false;
}
}
}
fn min_cost_to_supply_water(n: i32, wells: &[i32], pipes: &[[i32; 3]]) -> i32 {
unsafe {
ESIZE = 0;
for i in 0..n {
EDGES[ESIZE as usize][0] = 0;
EDGES[ESIZE as usize][1] = i + 1;
EDGES[ESIZE as usize][2] = wells[i as usize];
ESIZE += 1;
}
for i in 0..pipes.len() {
EDGES[ESIZE as usize][0] = pipes[i][0] as i32;
EDGES[ESIZE as usize][1] = pipes[i][1] as i32;
EDGES[ESIZE as usize][2] = pipes[i][2];
ESIZE += 1;
}
EDGES[0..ESIZE as usize].sort_by(|a, b| a[2].cmp(&b[2]));
build(n);
let mut ans = 0;
for i in 0..ESIZE {
if union(EDGES[i as usize][0], EDGES[i as usize][1]) {
ans += EDGES[i as usize][2];
}
}
return ans;
}
}
fn main() {
let n = 3;
let wells = [1, 2, 2];
let pipes = [[1, 2, 1], [2, 3, 1]];
let result = min_cost_to_supply_water(n, &wells, &pipes);
println!("Minimum cost to supply water: {}", result);
}
完全な C++ コードは次のとおりです。
#include <iostream>
#include <vector>
#include <array>
#include <algorithm>
using namespace std;
const int MAXN = 10010;
vector<array<int, 3>> edges;
int father[MAXN];
int size2[MAXN];
int help[MAXN];
void build(int n) {
for (int i = 0; i <= n; i++) {
father[i] = i;
size2[i] = 1;
}
}
int find(int i) {
int s = 0;
while (i != father[i]) {
help[s++] = i;
i = father[i];
}
while (s > 0) {
father[help[--s]] = i;
}
return i;
}
bool unionSet(int i, int j) {
int f1 = find(i);
int f2 = find(j);
if (f1 != f2) {
if (size2[f1] >= size2[f2]) {
father[f2] = f1;
size2[f1] += size2[f2];
}
else {
father[f1] = f2;
size2[f2] += size2[f1];
}
return true;
}
else {
return false;
}
}
int minCostToSupplyWater(int n, vector<int>& wells, vector<vector<int>>& pipes) {
edges.clear();
for (int i = 0; i < n; i++) {
edges.push_back({
0, i + 1, wells[i] });
}
for (int i = 0; i < pipes.size(); i++) {
edges.push_back({
pipes[i][0], pipes[i][1], pipes[i][2] });
}
sort(edges.begin(), edges.end(), [](const array<int, 3>& a, const array<int, 3>& b) {
return a[2] < b[2];
});
build(n);
int ans = 0;
for (int i = 0; i < edges.size(); i++) {
if (unionSet(edges[i][0], edges[i][1])) {
ans += edges[i][2];
}
}
return ans;
}
int main() {
int n = 3;
vector<int> wells = {
1, 2, 2 };
vector<vector<int>> pipes = {
{
1, 2, 1}, {
2, 3, 1} };
int result = minCostToSupplyWater(n, wells, pipes);
cout << "Minimum cost to supply water: " << result << endl;
return 0;
}
c の完全なコードは次のとおりです。
#include <stdio.h>
#include <stdlib.h>
#define MAXN 10010
int edges[MAXN << 1][3];
int esize;
int father[MAXN];
int size[MAXN];
int help[MAXN];
void build(int n) {
for (int i = 0; i <= n; i++) {
father[i] = i;
size[i] = 1;
}
}
int find(int i) {
int s = 0;
while (i != father[i]) {
help[s++] = i;
i = father[i];
}
while (s > 0) {
father[help[--s]] = i;
}
return i;
}
int union2(int i, int j) {
int f1 = find(i);
int f2 = find(j);
if (f1 != f2) {
if (size[f1] >= size[f2]) {
father[f2] = f1;
size[f1] += size[f2];
}
else {
father[f1] = f2;
size[f2] += size[f1];
}
return 1;
}
else {
return 0;
}
}
int minCostToSupplyWater(int n, int wells[], int pipes[][3], int pipesSize) {
esize = 0;
for (int i = 0; i < n; i++, esize++) {
edges[esize][0] = 0;
edges[esize][1] = i + 1;
edges[esize][2] = wells[i];
}
for (int i = 0; i < pipesSize; i++, esize++) {
edges[esize][0] = pipes[i][0];
edges[esize][1] = pipes[i][1];
edges[esize][2] = pipes[i][2];
}
// Sort edges based on the third column (weights)
for (int i = 0; i < esize; i++) {
for (int j = 0; j < esize - 1; j++) {
if (edges[j][2] > edges[j + 1][2]) {
int temp[3];
temp[0] = edges[j][0];
temp[1] = edges[j][1];
temp[2] = edges[j][2];
edges[j][0] = edges[j + 1][0];
edges[j][1] = edges[j + 1][1];
edges[j][2] = edges[j + 1][2];
edges[j + 1][0] = temp[0];
edges[j + 1][1] = temp[1];
edges[j + 1][2] = temp[2];
}
}
}
build(n);
int ans = 0;
for (int i = 0; i < esize; i++) {
if (union2(edges[i][0], edges[i][1])) {
ans += edges[i][2];
}
}
return ans;
}
int main() {
int n = 3;
int wells[] = {
1, 2, 2 };
int pipes[][3] = {
{
1, 2, 1}, {
2, 3, 1} };
int pipesSize = sizeof(pipes) / sizeof(pipes[0]);
int result = minCostToSupplyWater(n, wells, pipes, pipesSize);
printf("Minimum cost to supply water: %d\n", result);
return 0;
}