您的位置:首页 > 产品设计 > UI/UE

poj 2442 Sequence(堆)

2017-11-08 23:22 316 查看

题面

题意

给出一个m*n的矩阵,每行选择一个数相加,问所得的n个最小值是多少。

方法

将所有数一起处理必然会有漏洞,无法保证答案的正确或是时间,故可以一行一行处理,因为多考虑一行后的n个最小数必然由考虑这一行之前的n个最小值与这一行上的一些数相加得到,因而每次只需记录考虑上面几行后的最小值即可,问题就转换为了求两行上一些数相加的所有和中的最小的n个值。

这个问题可以用堆解决,因为两个序列都是升序,若a[i]+b[j]是其中一个最小值,那么a[i-1]和b[j-1]也是,以此性质,我们可以把a[1]与b中所有数的和加到堆里,每取出最小值,把a序列中的下一个数与b中那个数的和加到堆里:

例:a[1]+b[1]出堆后,将a[2]+b[1]加到堆里。

代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#define P pair<int,int>
#define mp make_pair
#define fi first
#define se second
using namespace std;

int T,n,m,num[110][2010],ans[2010],now[2010],tmp[2010];
priority_queue<P,vector<P>,greater<P> >pq;
P tmp2;

void read(int &u)
{
u=0;
register char ch=getchar();
while(ch<'0') ch=getchar();
while(ch>='0'&&ch<='9')
{
u*=10,u+=ch-'0',ch=getchar();
}
}

int main()
{
register int i,j,k;
cin>>T;
while(T--)
{
read(m),read(n);
for(i=1;i<=m;++i)
{
for(j=1;j<=n;++j)
{
read(num[i][j]);
}
sort(num[i]+1,num[i]+n+1);
}
for(i=1;i<=n;++i)
{
ans[i]=num[1][i];
}

for(i=2;i<=m;++i)
{
for(;!pq.empty();pq.pop());
for(j=1;j<=n;++j)
{
now[j]=1;
pq.push(mp(ans[j]+num[i][1],j));
}
for(j=1;j<=n;++j)
{
ans[j]=pq.top().fi;
tmp2=pq.top();
pq.pop();
now[tmp2.se]++;
tmp2.fi+=num[i][now[tmp2.se]]-num[i][now[tmp2.se]-1];
pq.push(tmp2);
}
}
for(i=1;i<=n;++i)
{
printf("%d ",ans[i]);
}
puts("");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: