题目描述:
东东在老家农村无聊,想种田。农田有 n 块,编号从 1~n。种田要灌氵
众所周知东东是一个魔法师,他可以消耗一定的 MP 在一块田上施展魔法,使得黄河之水天上来。他也可以消耗一定的 MP 在两块田的渠上建立传送门,使得这块田引用那块有水的田的水。 (1<=n<=3e2)
黄河之水天上来的消耗是 Wi,i 是农田编号 (1<=Wi<=1e5)
建立传送门的消耗是 Pij,i、j 是农田编号 (1<= Pij <=1e5, Pij = Pji, Pii =0)
东东为所有的田灌氵的最小消耗
Input:
第1行:一个数n
第2行到第n+1行:数wi
第n+2行到第2n+1行:矩阵即pij矩阵
sample input:
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
Output:
东东最小消耗的MP值。
9
个人思路:
-
未能实现的思路(不知道对不对):
首先,按照题目的描述,感觉像是求一个最小生成树,但是有不一样,因为点可以单独灌水。所以,按照朴素的kruscal的算法思想,只是在选边的时候要考虑到边权和点权的大小关系。如果我们选上的边反而增加了我们的MP花费,那么就不用选他。算是一个贪心,但是不知道对不对,简单提一嘴。。 -
正确且实现的思路:
在理解题意的基础上,我是这样想的,因为每个点都可以单独灌水,也就是从某种意义上来说,对于每个点,黄河水都是和他们相连的,只是需要花费MP。按照这种理解,也就是说黄河水是一个隐藏的顶点,而他与顶点的边权就是需要花费的MP,好,那么将n个点再加上黄河这个点,跑一个最小生成图就OK了。
代码块:
- 未能实现待调试但调不出来(2333):
#include<iostream>
#include<queue>
using namespace std;
const int maxn = 310;
struct node {
int u, v, w;
node(int x, int y, int value) { u = x, v = y, w = value; }
bool operator<(const node& q)const {
return w > q.w;
}
};
bool in_tree[maxn] = { false };
int n; int f_cost = 0;
int rnk[maxn], par[maxn],numz;
int wi[maxn], min_of_bchaji[maxn];
priority_queue<node> min_heap;
//priority_queue<int>min_heap2;
void init() { for (int i = 1; i <= n; ++i) par[i] = i, rnk[i] = 1; }
int find(int x) { return par[x] == x ? x : par[x] = find(par[x]); }
void unite(int x,int y) {
x = find(x); y = find(y);
if (x == y)return;
numz--;
if (rnk[x] > rnk[y]) { par[y] = x, rnk[x] = (rnk[y] += rnk[x]); min_of_bchaji[x] = min(min_of_bchaji[x], min_of_bchaji[y]); }
else { par[x] = y, rnk[y] = (rnk[x] += rnk[y]); min_of_bchaji[y] = min(min_of_bchaji[x], min_of_bchaji[y]); }
return;
}
void yinshui() {
while (!min_heap.empty()) {
node now = min_heap.top();
min_heap.pop();
if (find(now.u) != find(now.v)) {
//cout << now.w << endl;
if (in_tree[now.u] == false && in_tree[now.v] == false) {
if (now.w > wi[now.u] + wi[now.v])continue;
f_cost += now.w;
in_tree[now.u] = true; in_tree[now.v] = true;
unite(now.u, now.v);
}
else if (in_tree[now.u] == false && in_tree[now.v] == true) {
if (now.w > wi[now.u])continue;
f_cost += now.w;
in_tree[now.u] = true;
unite(now.u, now.v);
}
else if (in_tree[now.u] == true && in_tree[now.v] == false) {
if (now.w > wi[now.v])continue;
f_cost += now.w;
in_tree[now.v] = true;
unite(now.u, now.v);
}
else if (in_tree[now.u] == true && in_tree[now.v] == true) {
if (now.w > min(min_of_bchaji[find(now.u)], min_of_bchaji[find(now.v)])) {
f_cost = f_cost + min_of_bchaji[find(now.u)] + min_of_bchaji[find(now.v)];
continue;
}
f_cost += now.w;
unite(now.u, now.v);
}
}
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> wi[i];
min_of_bchaji[i] = wi[i];
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
int w;
cin >> w;
if (i == j)continue;
min_heap.push(node(i, j, w));
}
}
numz = n;
init();
yinshui();
if (numz == 1)//如果最后只有一棵树
f_cost += min_of_bchaji[find(2)];
for (int i = 1; i <= n; ++i) {
if (in_tree[i] == false) f_cost += wi[i];
}
cout << f_cost << endl;
return 0;
}
- 正确的代码:
#include<iostream>
#include<queue>
using namespace std;
const int maxn = 310;
struct node {
int u, v, w;
node(int x, int y, int value) { u = x, v = y, w = value; }
bool operator<(const node& q)const {
return w > q.w;
}
};
// define super root n+1;
int n; int f_cost = 0;
int rnk[maxn], par[maxn];
int wi[maxn];
priority_queue<node> min_heap;
void init() { for (int i = 1; i <= n; ++i) par[i] = i, rnk[i] = 1; }
int find(int x) { return par[x] == x ? x : par[x] = find(par[x]); }
void unite(int x,int y) {
x = find(x); y = find(y);
if (x == y)return;
if (rnk[x] > rnk[y]) { par[y] = x, rnk[x] = (rnk[y] += rnk[x]); }
else { par[x] = y, rnk[y] = (rnk[x] += rnk[y]); }
return;
}
void yinshui() {
while (!min_heap.empty()) {
node now = min_heap.top();
min_heap.pop();
if (find(now.u) != find(now.v)) {
f_cost += now.w;
unite(now.u, now.v);
}
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> wi[i];
min_heap.push(node(n + 1, i, wi[i]));
min_heap.push(node(i, n + 1, wi[i]));
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
int w;
cin >> w;
if (i == j)continue;
min_heap.push(node(i, j, w));
}
}
init();
yinshui();
cout << f_cost << endl;
return 0;
}