問題簡述:
輸入 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]);
}
}