Loading

7594. 【2022.07.02GDOI模拟】网上购物(shopping)

Description

双十一是最佳的购物时间,Bob当然不会错过这个机会。由于抢购太疯狂了,平台不得不提出限购:每种商品的数量只有1个,且必须在双十一零点起的规定时间内完成下单。具体来说,平台上有n种不同的商品在销售,其中第i种商品的价格为wi,且必须在di分钟(含)内完成下单,每种商品下单时间均需要花费1分钟。

Bob想用最少的钱购买最多的商品,此刻他正在思考他的购物清单。Bob采用以下方式来比较两个购物清单的优劣:先比较商品的数量,数量多的优于数量少的,数量相同的情况下比较花费,花费少的优于花费多的。

Bob将把他所有可能的购物清单进行排序,优先考虑前k好的购物清单。现在他找到你,请你帮他计算前k好的清单中商品的数量及其花费。

Solution

\(k\) 优秀,想到 \(A^*\)

首先预处理出状态 \((i,j)\) 到终点的最短路。具体来说,\(f_{i,j}\) 表示到第 \(i\) 个商品,买了 \(j\) 个的最小花费。

有转移方程 \(f_{i,j}=\min(f_{i+1,j},(f_{i+1,j+1}+w_i)[d_i>j])\)

随后正向枚举每个商品,并不断的加入到堆中,最后取出堆的前 \(k\) 个作为下次添加时进行对比的方案。

Code

#include<cstdio>
#include<algorithm>
#define N 2005
#define inf 12345678987654
#define ll long long
using namespace std;
int n,k,tot,num;
ll f[N][N];
struct node
{
    int x,y;
    ll z;
}a[N],b[N],c[N];
bool cmp1(node x,node y) {return x.y<y.y;}
bool cmp2(node x,node y) {return x.z+f[x.x][x.y]<y.z+f[y.x][y.y];}
int main()
{
    freopen("shopping.in","r",stdin);
    freopen("shopping.out","w",stdout);
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;++i)
        scanf("%d%d",&c[i].x,&c[i].y);
    sort(c+1,c+n+1,cmp1);
    for (int i=0;i<=n;++i)
        f[n][i]=(n-i)*inf;
    for (int i=n-1;i>=0;--i)
        for (int j=0;j<=i;++j)
            if (c[i+1].y>j) f[i][j]=min(f[i+1][j],f[i+1][j+1]+c[i+1].x);
            else f[i][j]=f[i+1][j];
    tot=1;
    for (int i=1;i<=n;++i)
    {
        num=0;
        for (int j=1;j<=tot;++j)
        {
            ++num;
            b[num].x=a[j].x+1;b[num].y=a[j].y;b[num].z=a[j].z;
            if (a[j].y<c[i].y)
            {
                ++num;
                b[num].x=a[j].x+1;b[num].y=a[j].y+1;b[num].z=a[j].z+c[i].x;
            }
        }
        sort(b+1,b+num+1,cmp2);
        tot=min(num,k);
        for (int j=1;j<=tot;++j)
            a[j]=b[j];
    }
    for (int i=1;i<=k;++i)
        printf("%d %lld\n",a[i].y,a[i].z);
    return 0;
}
posted @ 2022-07-05 08:29  Thunder_S  阅读(69)  评论(0编辑  收藏  举报