HDU 1512 Monkey King(左偏树)

来源:互联网 发布:windows系统镜像 编辑:程序博客网 时间:2024/04/30 14:41

题目链接:点击打开链接

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

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

代码:

// HDU 1512 Monkey King.cpp  1388ms#include "stdafx.h"#include <cstdio>#include <cstring>#include <iostream>using namespace std;#define MAXN 100005int 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 100005class 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;}



原创粉丝点击