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;
}
标签:02GDOI,shopping,int,7594,购物,花费,商品,清单,Bob 来源: https://www.cnblogs.com/Livingston/p/16445090.html