题目链接:
http://poj.org/problem?id=2442
题意:
给你一个 m × n m×n m×n的矩阵,让你从 m m m行,每行选一个数,得到一个序列,这样共有 n n n m ^m m种序列,让你求前 n n n小的序列和,并输出这n个序列和;
分析:
用有限队列或二叉堆不断维护前n小的序列和,假设读入序列 a a a时已经得到此之前的前n小序列和,那么通过之前得到的前n小序列和来继续不断维护;
代码:
优先队列实现:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
const int inf=0x7f7f7f7f;
const int maxn=1e1+50;
const int N=5e6+50;
typedef long long ll;
typedef struct{
ll u,v,next,w;
}Edge;
Edge e[N];
int cnt,head[N];
inline void add(int u,int v){
e[cnt].u=u;
e[cnt].v=v;
//e[cnt].w=w;
// e[cnt].f=f;
e[cnt].next=head[u];
head[u]=cnt++;
// e[cnt].u=v;
// e[cnt].v=u;
// e[cnt].w=0;
// e[cnt].f=-f;
// e[cnt].next=head[v];
// head[v]=cnt++;
}
inline int read()
{
int x = 0;
int f = 1;
char c = getchar();
while (c<'0' || c>'9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0'&&c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x*f;
}
int t,n,m,a[2110],b[2110];
void solve(){
priority_queue<int>q;
for(int i=0;i<m;i++){
q.push(a[i]+b[0]);
}
for(int i=0;i<m;i++){
for(int j=1;j<m;j++){
int x=a[i]+b[j];
if(x<q.top()){
q.pop();
q.push(x);
}
else break;
}
}
for(int i=0;i<m;i++){
a[m-i-1]=q.top();
//cout<<q.top()<<endl;
q.pop();
}
}
int main() {
cin>>t;
while(t--){
cin>>n>>m;
for(int i=0;i<m;i++){
scanf("%d",&a[i]);
}
sort(a,a+m);
for(int i=1;i<n;i++){
for(int j=0;j<m;j++){
scanf("%d",&b[j]);
}
sort(b,b+m);
solve();
}
for(int i=0;i<m-1;i++){
cout<<a[i]<<" ";
}
cout<<a[m-1]<<endl;
}
return 0;
}
二叉堆实现:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
const int inf=0x7f7f7f7f;
const int maxn=1e1+50;
const int N=5e6+50;
typedef long long ll;
typedef struct{
ll u,v,next,w;
}Edge;
Edge e[N];
int cnt,head[N];
inline void add(int u,int v){
e[cnt].u=u;
e[cnt].v=v;
//e[cnt].w=w;
// e[cnt].f=f;
e[cnt].next=head[u];
head[u]=cnt++;
// e[cnt].u=v;
// e[cnt].v=u;
// e[cnt].w=0;
// e[cnt].f=-f;
// e[cnt].next=head[v];
// head[v]=cnt++;
}
inline int read()
{
int x = 0;
int f = 1;
char c = getchar();
while (c<'0' || c>'9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0'&&c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x*f;
}
struct BH{
int heap[2100],cot;
BH(){
memset(heap,0,sizeof(heap));
cot=0;
}
void up(int pos){
while(pos>1){
if(heap[pos]>heap[pos/2]){
swap(heap[pos],heap[pos/2]);
pos/=2;
}
else break;
}
}
void down(int pos){
int s=pos*2;
while(s<=cot){
if(s<cot&&heap[s]<heap[s+1])s++;//左右子节点中取较大者
if(heap[s]>heap[pos]){ //如果子节点值大于父节点值,就进行更新
swap(heap[s],heap[pos]);
pos=s;//将pos定位为进行更新的子节点,继续往下更新
s=pos*2;//s再次赋值为当前访问节点的左子节点;
}
else break;
}
}
int gettop(){
return heap[1];
}
void insert(int val){
heap[++cot]=val;
up(cot);
}
void extract(){//删除堆顶元素
heap[1]=heap[cot--];
down(1);
}
void remove(int pos){//删除位置为pos元素
heap[pos]=heap[cot--];
up(pos),down(pos);//先up,后down,顺序不能改变
}
};
int t,m,n,a[2210],b[2210];
int main() {
cin>>t;
while(t--){
BH bh;
cin>>m>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n);
for(int i=1;i<m;i++){
for(int j=0;j<n;j++){
cin>>b[j];
}
sort(b,b+n);
for(int j=0;j<n;j++){
bh.insert(b[j]+a[0]);
}
/*for(int j=0;j<n;j++)
cout<<b[j]<<endl;*/
for(int j=1;j<n;j++){
for(int k=0;k<n;k++){
int x=a[j]+b[k];
//cout<<bh.heap[1]<<endl;
if(x<bh.heap[1]){
bh.extract();
bh.insert(x);
}
else break;
}
}
for(int j=n-1;j>=0;j--){
a[j]=bh.heap[1];
bh.extract();
}
}
for(int i=0;i<n-1;i++){
cout<<a[i]<<" ";
}
cout<<a[n-1]<<endl;
}
return 0;
}
(仅供个人理解)