AtCoder Beginner Contest 123 D

题目连接ios

题目大意:数组

给出a,b,c三个数组,数组长度分别为x,y,z(1<=x,y,z<=1000),从这三个数组各挑选一个元素相加能够有x*y*z种可能,如今让你输出前k(k<=min(3000,x*y*z))个大的状况。spa

分析:code

若是不给出限制的话,就直接遍历一遍,可是x*y*z如今明显是会超时的,可是k是小于3000的,因此这道题的解决方法是广搜。首先,肯定起点,那么一定是三个数组最大的相加,那么应该怎么走呢?明显的,题目要求从大到小输出,比起点小的有哪些状况,有三种,第一种a的第二大+b的第一大+c的第一大,第二种a的第一大+b的第二大+c的第一大,第三种a的第一大+b的第一大+c的第二大,想到了这三种状况,那么路径就已经规划好了,但到底该选哪条呢?这里就要用到优先队列,每次选择最大的就能够了。队列

代码:get

#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;
}