POJ2442 Sequence 堆

题目链接

http://poj.org/problem?id=2442

分析

两两合并,对于两个序列 A A A B B B,先将 A [ 1 ] + B [ i ] A[1] + B[i] A[1]+B[i] 加入堆中, 1 ≤ i ≤ n 1 \leq i \leq n 1in

每次取出的堆顶,即是当前最小和,设取出了 A [ i ] + B [ j ] A[i] + B[j] A[i]+B[j],再将 A [ i + 1 ] + B [ j ] A[i + 1] + B[j] A[i+1]+B[j] 加入堆中。

AC代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

inline int read() {
	int num = 0;
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9')
		num = num * 10 + c - '0', c = getchar();
	return num;
}

const int maxn = 2e3 + 5;

struct Node {
	int a, sum;

	Node(int a = 0, int s = -1) : a(a), sum(s) {}

	bool operator < (const Node& rhs) const {
		return sum < rhs.sum;
	}
};

struct Heap {
	int tot;
	Node h[maxn];

	void up(int p) {
		while (p > 1) {
			if (h[p] < h[p / 2]) swap(h[p], h[p / 2]), p /= 2;
			else break;
		}
	}

	void down(int p) {
		while (2 * p <= tot) {
			int q = 2 * p;
			if (q + 1 <= tot && h[q + 1] < h[q]) ++q;
			if (h[q] < h[p]) swap(h[q], h[p]), p = q;
			else break;
		}
	}

	void insert(Node x) {
		h[++tot] = x;
		up(tot);
	}

	Node get_top() {
		return h[1];
	}

	void remove(int p = 1) {
		h[p] = h[tot--];
		up(p), down(p);
	}
} h;

int a[maxn], b[maxn], c[maxn];

int main() {
	int t = read();
	while (t--) {
		int m = read(), n = read();
		for (int i = 1; i <= n; ++i) a[i] = read();
		sort(a + 1, a + n + 1);
		for (int i = 2; i <= m; ++i) {
			h.tot = 0;
			for (int j = 1; j <= n; ++j) b[j] = read();
			sort(b + 1, b + n + 1);
			for (int j = 1; j <= n; ++j) h.insert(Node(1, a[1] + b[j]));
			for (int j = 1; j <= n; ++j) {
				int p = h.get_top().a;
				c[j] = h.get_top().sum;
				h.remove();
				h.insert(Node(p + 1, a[p + 1] + c[j] - a[p]));
			}
			for (int j = 1; j <= n; ++j) a[j] = c[j];
		}
		for (int i = 1; i <= n; ++i) printf("%d ", a[i]);
		puts("");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值