HDU 1512 Monkey King(左偏树)

本文介绍了一种使用左偏树(一种特殊的堆结构)解决猴子打架问题的方法。该问题涉及猴子之间的战斗规则和组合并操作。文章提供了两种实现方式的代码示例,并讨论了基于类封装的实现相较于直接过程式编程的优势与不足。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:点击打开链接

题意:一群猴子,每个猴子均在唯一的一个组里,可单独成组。当两个猴子要打架时,若在同一组,不可以打架,若不在一组,每个猴子找到本组中最强壮的去迎战,打完架的两个猴子,强壮值减半,而且这两组猴子合并为一组。

由最强壮的猴子迎战,而且要合并组,可以想到左偏树(有合并操作的堆)。不同于简单的左偏树模板的是,由于要尽快的找到某个节点的堆顶,借助于并查集的思路,存每个节点的父亲节点,而且还要写下滤函数,当猴子的强壮值改变,进行下滤。

代码:

// HDU 1512 Monkey King.cpp  1388ms
#include "stdafx.h"
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define MAXN 100005
int value[MAXN], lef[MAXN], rig[MAXN], fa[MAXN], dist[MAXN];
int n;
void init() {
	for (int i = 1; i <= n; i++) {
		scanf("%d", &value[i]);
		lef[i] = rig[i] = -1;
		dist[i] = 0;
		fa[i] = i;
	}
}
int getFather(int x) {//并查集思想
	return fa[x] = (fa[x] == x ? x : getFather(fa[x]));
}
int merge(int x, int y) {
	if (x == -1) {
		return y;
	}
	if (y == -1) {
		return x;
	}
	int a = (value[x] > value[y] ? x : y);
	int b = (a == x ? y : x);
	rig[a] = merge(rig[a], b);
	if (lef[a] == -1 || dist[lef[a]] < dist[rig[a]]) {
		swap(lef[a], rig[a]);
	}
	if (lef[a] != -1) {
		fa[lef[a]] = a;
	}
	if (rig[a] != -1) {
		fa[rig[a]] = a;
	}
	dist[a] = dist[rig[a]] + 1;
	return a;
}
void down(int x) {//下滤
	int i, child;
	int te = value[x];
	for (i = x; lef[i] != -1; i = child) {
		child = lef[i];
		if (rig[i] != -1 && value[rig[i]] > value[lef[i]]) {
			child = rig[i];
		}
		if (te > value[child]) {
			break;
		}
		value[i] = value[child];
	}
	value[i] = te;
}
void decrease(int x) {
	value[x] /= 2;
	down(x);
}
int main(){
	int m,x,y;
	while (scanf("%d", &n) != EOF) {
		init();
		scanf("%d", &m);
		for (int i = 0; i < m; i++) {
			scanf("%d%d", &x, &y);
			int a = getFather(x);
			int b = getFather(y);
			if (a == b) {
				printf("-1\n");
			}
			else {
				decrease(a);
				decrease(b);
				int re = merge(a, b);
				printf("%d\n", value[re]);
			}
		}
	}
    return 0;
}


一开始写的基于C++类封装的实现:

这个写法更快,不过,虽然基于类封装实现更能体现面向对象的思想,但这种思想更适合用于工程开发,做算法题注重思维,如何使用更少的时间和空间去解决问题才是关键,有的题目面向对象的做法开销会比较大,不一定是最佳方案。

// HDU 1512 Monkey King.cpp  1123ms
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define MAXN 100005
class LeftistTree {
private:
	int n;
	int value[MAXN], left[MAXN], right[MAXN], fa[MAXN], dist[MAXN];
public:
	void init(int t) {
		n = t;
		for (int i = 1; i <= n; i++) {
			scanf("%d", &value[i]);
			left[i] = right[i] = -1;
			dist[i] = 0;
			fa[i] = i;
		}
	}
	int getFather(int x) {
		return fa[x] = (fa[x] == x ? x : getFather(fa[x]));
	}
	int merge(int x, int y) {
		if (x == -1) {
			return y;
		}
		if (y == -1) {
			return x;
		}
		int a = (value[x] > value[y] ? x : y);
		int b = (a == x ? y : x);
		right[a] = merge(right[a], b);
		fa[right[a]] = a;
		if (left[a] == -1 || dist[left[a]] < dist[right[a]]) {
			swap(left[a], right[a]);
		}
		if(left[a] != -1){
			fa[left[a]] = a;
		}
		if(right[a] != -1){
			fa[right[a]] = a;
		}
		dist[a] = dist[right[a]] + 1;
		return a;
	}
	void decrease(int x) {
		value[x] /= 2;
		down(x);
	}
	void down(int x) {
		int i,child;
		int te = value[x];
		for (i = x; left[i] != -1; i = child) {
			child = left[i];
			if(right[i] != -1 && value[right[i]] > value[left[i]]){
				child = right[i];
			}
			if (te > value[child]) {
				break;
			}
			value[i] = value[child];
		}
		value[i] = te;
	}
	int getValue(int x) {
		return value[x];
	}
};
int main(){
	int n,m,x,y;
	LeftistTree *tree = new LeftistTree();
	while (scanf("%d", &n) != EOF) {
		tree->init(n);
		scanf("%d", &m);
		for (int i = 0; i < m; i++) {
			scanf("%d%d", &x, &y);
			int a = tree->getFather(x);
			int b = tree->getFather(y);
			if (a == b) {
				printf("-1\n");
			}
			else {
				tree->decrease(a);
				tree->decrease(b);
				int re = tree->merge(a, b);
				printf("%d\n", tree->getValue(re));
			}
		}
	}
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值