题目链接:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3148
题目分析:
k个数的和最小,那么任意两行的那两个数的和也最小,否则就可以找到比该值更小的数。
可以先求两行中k个最小和,再进行多路归并即可。
对于从 k 行中取出 2 个行最小值可以理解,但是对于多路归并还不是很理解,先贴下《信息竞赛入门经典》里面的 代码,mark 下。
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define minD 562510 #define minK 760 #define INF 0x3f3f3f3f int N, D, min[4 * minD], a[minK][minK], ans[minK]; void init() { int i, j; for(i = 0; i < N; i ++) { for(j = 0; j < N; j ++) scanf("%d", &a[i][j]); std::sort(a[i], a[i] + N); } for(D = 1; D < N * N + 2; D <<= 1); memset(min, 0x3f, sizeof(min[0]) * 2 * D); } void update(int i) { for(; i ^ 1; i >>= 1) min[i >> 1] = std::min(min[i], min[i ^ 1]); } int getid() { int i; for(i = 1; i < D;) { if(min[i << 1] == min[i]) i <<= 1; else i = i << 1 | 1; } return i; } void pop() { int i = getid(); min[i] = INF, update(i); } void push(int x, int y, int v) { int i = x * N + y; min[D + i] = v, update(D + i); } void top(int &x, int &y, int &v) { int i = getid() - D; x = i / N, y = i % N, v = min[D + i]; } void solve() { int i, j, x, y, v, cnt; for(i = 1; i < N; i ++) { while(min[1] != INF) pop(); cnt = 0; push(0, 0, a[i - 1][0] + a[i][0]); while(cnt < N) { top(x, y, v), pop(); ans[cnt ++] = v; if(x < N) push(x + 1, y, a[i - 1][x + 1] + a[i][y]); if(y < N) push(x, y + 1, a[i - 1][x] + a[i][y + 1]); } for(j = 0; j < N; j ++) a[i][j] = ans[j]; } printf("%d", a[N - 1][0]); for(i = 1; i < N; i ++) printf(" %d", a[N - 1][i]); printf("\n"); } int main() { while(scanf("%d", &N) == 1) { init(); solve(); } return 0; }
作者:a1006570862 发表于2013-11-27 0:18:30 原文链接
阅读:111 评论:0 查看评论