Week6—C—掌握魔法的东东

题目描述:

东东在老家农村无聊,想种田。农田有 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值