题目大意:
给出a,b,c三个数组,数组长度分别为x,y,z(1<=x,y,z<=1000),从这三个数组各挑选一个元素相加可以有x*y*z种可能,现在让你输出前k(k<=min(3000,x*y*z))个大的情况。
分析:
如果不给出限制的话,就直接遍历一遍,但是x*y*z现在明显是会超时的,但是k是小于3000的,所以这道题的解决方法是广搜。首先,确定起点,那么必定是三个数组最大的相加,那么应该怎么走呢?明显的,题目要求从大到小输出,比起点小的有哪些情况,有三种,第一种a的第二大+b的第一大+c的第一大,第二种a的第一大+b的第二大+c的第一大,第三种a的第一大+b的第一大+c的第二大,想到了这三种情况,那么路径就已经规划好了,但到底该选哪条呢?这里就要用到优先队列,每次选择最大的就可以了。
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<cmath>
#include<map>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1000+5,dx[]={0,0,1},dy[]={0,1,0},dz[]={1,0,0};
bool cmp(ll x,ll y)//从大到小
{
return x>y;
}
struct P{
int x,y,z;
ll w;
P(){};
P(int a,int b,int c,ll ww)
{
x=a;y=b;z=c;w=ww;
}
friend bool operator<(const P &p1,const P &p2)//从大到小
{
return p1.w<p2.w;
}
};
priority_queue<P>q;
ll a[N],b[N],c[N];
int k;
map<ll,int>mmp;
ll zh(int x,int y,int z)//将x,y,z转换成一个长整型,用来映射
{
return x*100000000+y*10000+z;
}
int x,y,z;
void bfs()
{
mmp[0]=1;
q.push(P(0,0,0,a[0]+b[0]+c[0]));
while(!q.empty()&&k)
{
P p=q.top();
q.pop();
k--;
printf("%lld\n",p.w);
for(int i=0;i<3;i++)
{
int nx=p.x+dx[i],ny=p.y+dy[i],nz=p.z+dz[i];
if(nx<x&&ny<y&&nz<z&&!mmp[zh(nx,ny,nz)])
{
mmp[zh(nx,ny,nz)]=1;
q.push(P(nx,ny,nz,a[nx]+b[ny]+c[nz]));
}
}
}
while(!q.empty()){
q.pop();
}
}
int main()
{
scanf("%d%d%d%d",&x,&y,&z,&k);
for(int i=0;i<x;i++)
{
scanf("%lld",&a[i]);
}
for(int i=0;i<y;i++)
{
scanf("%lld",&b[i]);
}
for(int i=0;i<z;i++)
{
scanf("%lld",&c[i]);
}
sort(a,a+x,cmp);
sort(b,b+y,cmp);
sort(c,c+z,cmp);
bfs();
return 0;
}