【注】
标题有点长啊。首先说明清楚其实就只是【Uva】11997 K Smallest Sum这一道题的题解而已……
【题意】
给
K
个长度为
【数据范围】
【分析】
其实就是把【CodeVS】1245的两个数组变成了K个数组而已。
既然我们已经会求两个的了,那么就尝试着把2个的方法与K个的方法建立一定的联系。
考虑从2个、3个、4个、…、K个这样来依次求。
每次我们对第i-1个和第i个数组进行求前K小,然后把它作为新的一个数组和接下来的继续求前K小。
这是成立的,因为不在前K小的和一定不是答案。
这样问题就解决了。
时间复杂度:
O(k2logk)
空间复杂度:
O(k)
【代码】
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int K=1024;
const int S=30000;
int k;
int a[K],b[K];
inline int Read(void)
{
int s=0; char c=getchar();
for (;!isdigit(c);c=getchar());
for (;isdigit(c);c=getchar()) s=s*10+c-'0';
return s;
}
int t[S];
int len;
void Update(void)
{
len=0;
for (int i=1;i<=k;i++)
for (int j=1;i*j<=k;j++) t[++len]=a[i]+b[j];
sort(t+1,t+len+1);
for (int i=1;i<=k;i++) a[i]=t[i];
}
int main(void)
{
for (;~scanf("%d",&k);)
{
for (int i=1;i<=k;i++) a[i]=Read();
sort(a+1,a+k+1);
for (int i=2;i<=k;i++)
{
for (int j=1;j<=k;j++) b[j]=Read();
sort(b+1,b+k+1);
Update();
}
for (int i=1;i<k;i++) printf("%d ",a[i]);
printf("%d\n",a[k]);
}
return 0;
}
【小结】
有N步决策的求前K小的问题:可以考虑一步步来解决。
因为如果当前这步不在前K小的范围内,那么肯定不是答案,否则会有至少K个比它小的,矛盾。