Giả sử chúng ta có hai danh sách costs_from và costs_to cùng kích thước, trong đó mỗi chỉ số i đại diện cho một thành phố. Việc xây dựng một đường đi một chiều từ thành phố i đến j có chi phí là costs_from[i] + costs_to[j]. Chúng ta cũng có một danh sách các cạnh edges trong đó mỗi cạnh [x, y] cho biết đã có sẵn một đường đi một chiều từ thành phố x đến y. Nếu muốn đi đến bất kỳ thành phố nào từ thành phố 0, ta cần tìm chi phí tối thiểu để xây dựng các đường đi cần thiết.
Ví dụ, với đầu vào costs_from = [6, 2, 2, 12], costs_to = [2, 2, 3, 2], edges = [[0, 3]], kết quả sẽ là 13. Ta có thể đi từ 0 đến 2 với chi phí 9 (6+3), sau đó từ 2 đến 1 với chi phí 4 (2+2). Đường đi đến 3 từ 0 đã có sẵn. Tổng chi phí: 9 + 4 = 13.
Giải thuật
Các bước thực hiện như sau:
n:= kích thước củacosts_fromret:= 0- Định nghĩa hai map
edgesvàredges(cạnh ngược) - Duyệt qua tất cả các phần tử
ittrongg:- Thêm
it[1]vàoedges[it[0]] - Thêm
it[0]vàoredges[it[1]]
- Thêm
from_cost:= vô cực- Định nghĩa tập hợp
visitedvàreachable - Định nghĩa hàm
dfs(i):- Nếu
ichưa được thăm và chưa thể đến được:- Đánh dấu
iđã thăm - Đệ quy
dfs(j)cho mọijtrongedges[i] - Thêm
ivào mảngpo(thứ tự hậu tố)
- Đánh dấu
- Nếu
- Định nghĩa hàm
dfs2(i):- Nếu
iđã thăm → trả về true - Nếu
iđã có thể đến được → trả về false - Đánh dấu
iđã thăm và có thể đến được ret := true- Với mọi
jtrongredges[i]:ret &= dfs2(j) - Trả về
ret
- Nếu
- Khởi tạo hàng đợi
q, thêm 0 vàoreachablevàq - Khi
qkhông rỗng:- Lấy phần tử đầu
nodevà loại bỏ khỏiq - Với mọi
itrongedges[node]:- Nếu
ichưa trongreachable: thêm vàoreachablevàq
- Nếu
- Cập nhật
from_cost = min(from_cost, costs_from[node])
- Lấy phần tử đầu
global_min:= phần tử nhỏ nhất củacosts_fromret := ret + from_cost - global_min- Định nghĩa mảng
po - Với
itừ 0 đếnn-1: gọidfs(i) - Đảo ngược mảng
po - Với mỗi
itrongpo:- Nếu
iđã trongreachable: bỏ qua - Xóa
visited initial := dfs2(i)- Nếu
initiallà true:best := inf- Với mọi
jtrongvisited:best = min(best, costs_to[j]) ret := ret + global_min + best
- Nếu
- Trả về
ret
Ví dụ minh họa
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
int solve(vector<int>& costs_from, vector<int>& costs_to, vector<vector<int>>& g) {
int n = costs_from.size();
int ret = 0;
map<int, vector<int>> edges;
map<int, vector<int>> redges;
for (auto& it : g) {
edges[it[0]].push_back(it[1]);
redges[it[1]].push_back(it[0]);
}
int from_cost = INT_MAX;
set<int> visited;
set<int> reachable;
queue<int> q;
reachable.insert(0);
q.push(0);
while (!q.empty()) {
int node = q.front();
q.pop();
for (int i : edges[node]) {
if (!reachable.count(i)) {
reachable.insert(i);
q.push(i);
}
}
from_cost = min(from_cost, costs_from[node]);
}
int global_min = *min_element(costs_from.begin(), costs_from.end());
ret += from_cost - global_min;
vector<int> po;
function<void(int)> dfs = [&](int i) {
if (!visited.count(i) && !reachable.count(i)) {
visited.insert(i);
for (int j : edges[i]) {
dfs(j);
}
po.push_back(i);
}
};
for (int i = 0; i < n; i++) dfs(i);
reverse(po.begin(), po.end());
function<bool(int)> dfs2 = [&](int i) {
if (visited.count(i)) return true;
if (reachable.count(i)) return false;
visited.insert(i);
reachable.insert(i);
bool ret = true;
for (int j : redges[i]) {
ret &= dfs2(j);
}
return ret;
};
for (int i : po) {
if (reachable.count(i)) continue;
visited.clear();
bool initial = dfs2(i);
if (initial) {
int best = INT_MAX;
for (int j : visited) {
best = min(best, costs_to[j]);
}
ret += global_min + best;
}
}
return ret;
}
};
int solve(vector<int>& costs_from, vector<int>& costs_to, vector<vector<int>>& edges) {
return (new Solution())->solve(costs_from, costs_to, edges);
}
int main() {
vector<int> costs_from = {6, 2, 2, 12};
vector<int> costs_to = {2, 2, 3, 2};
vector<vector<int>> edges = {{0, 3}};
cout << solve(costs_from, costs_to, edges);
}
Đầu vào
{6, 2, 2, 12}, {2, 2, 3, 2}, {{0, 3}}
Đầu ra
13