2015-07-14
问题简述:
输入 m 条序列,每条序列有 n 个整数。对每一个序列取一个数,可随机取出 m 个数,求这 m 个数的和,会有 m^n 种情况,输出其中和最小的 n 个数。
原题链接:http://poj.org/problem?id=2442
解题思路:
暴力求解会遍历 m^n 次,时间复杂度太高,不适合这个题,故采用其他方法,比如堆。
运算过程中,我们只需要维护好大小为 n 的堆,以实现最后这个堆就是所求 n 个数。
构造一个和序列 sum,初始化和序列 sum 为第一个序列;
从第二个序列开始,对每一个序列计算下一个序列的第一个数与当前和序列的和,存在一个新序列 ans 中。
用下一个序列的下一个数与当前和序列的每一个数相加,将和值与 ans 比较,若小于 ans 中的最大数,则将此和值插入 ans。
注:以上过程每一次使用一个新序列时,都需要对其进行升序排列。
源代码:
/*
OJ: POJ
ID: 3013216109
TAST: 2442.Sequence
LANG: C++
NOTE: STL堆
*/
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_M=105,MAX_N=2005;
int a[MAX_M][MAX_N];
int sum[MAX_N],ans[MAX_N];
int main()
{
int t,m,n,i,j,k;
scanf("%d",&t);
while(t--) {
scanf("%d %d",&m,&n);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf("%d",&a[i][j]);
for(j=0;j<n;j++)
sum[j]=a[0][j];
for(i=1;i<m;i++) {
sort(sum,sum+n);
sort(a[i],a[i]+n);
for(k=0;k<n;k++)
ans[k]=sum[k]+a[i][0];
make_heap(ans,ans+n);
for(j=1;j<n;j++) {
for(k=0;k<n;k++) {
int x=sum[k]+a[i][j];
if(x<ans[0]) {
pop_heap(ans,ans+n);
ans[n-1]=x;
push_heap(ans,ans+n);
}
else break;
}
}
for(j=0;j<n;j++)
sum[j]=ans[j];
}
sort(sum,sum+n);
for(j=0;j<n-1;j++)
printf("%d ",sum[j]);
printf("%d\n",sum[n-1]);
}
}