题目大意:有几种包裹需要打包,每种包括有一定的体积,每种包裹可能有多个。有一个运输公司提供了多种包裹服务,每种有一定的尺寸和价格,多加一种服务需要多付一定数量的钱。为了节省掉这一部分的钱,小的包裹可以使用大尺寸来运输,但大的不能用小的来运输,求最小价格。
首先对服务排序,根据尺寸从大到小排序,如果有某些服务相对于某个其他的服务,尺寸小价格反而贵,则这种服务直接舍去。
然后对包裹按尺寸从大到小排序。
用c[i]表示第i种服务能运输的包裹的最靠前的编号是哪个。用sum[i]表示前i种包裹的数量总和。用d[i][j]表示前i种服务运输前j个物品需要的最小费用。a[i].price表示第i种服务的价格。
分是否使用第i种服务讨论。如果不使用就是d[i-1][j],如果使用,根据贪心原理,能用第i种服务的都应尽量用第i种(服务是排序过的,第i种服务的价格低于前面任意一种)。
状态转移方程:d[i][j]=min { d[i-1][j],d[i-1][c[i]-1]+(sum[j]-sum[c[i]-1])a[i].price+C}
#include<stdio.h>
#include<stdlib.h>
typedef long long LL;
typedef struct
{
int siz;
int pri;
}Pac;
typedef struct
{
int siz;
int num;
}Box;
Pac a[1010];
Box b[1010];
int c[1010];
LL d[2][1010];
Pac e[1010];
int sum[1010];
int Cmpa(const Pac*i,const Pac*j);
int Cmpb(const Box*i,const Box*j);
int main(void)
{
int i,j,u,p,n,m,qi,cur,top;
LL q;
qi=0;
scanf("%d%d%d",&p,&n,&m);
while((p!=0)||(n!=0)||(m!=0))
{
qi++;
for(i=1;i<=n;i++)
{
scanf("%d%d",&e[i].siz,&e[i].pri);
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&b[i].siz,&b[i].num);
}
qsort(e+1,n,sizeof(e[1]),Cmpa);
qsort(b+1,m,sizeof(b[1]),Cmpb);
if((n==0)||(e[1].siz<b[1].siz))
{
printf("case %d: not possible\n",qi);
}
else
{
top=1;
a[1]=e[1];
for(i=2;i<=n;i++)
{
if(e[i].siz<b[m].siz)
{
break;
}
if(e[i].pri<e[i-1].pri)
{
top++;
a[top]=e[i];
}
}
sum[1]=b[1].num;
for(i=2;i<=m;i++)
{
sum[i]=sum[i-1]+b[i].num;
}
u=1;
for(i=1;i<=top;i++)
{
while(a[i].siz<b[u].siz)
{
u++;
}
c[i]=u;
}
cur=1;
for(j=1;j<=m;j++)
{
d[1][0]=0;
d[1][j]=(LL)sum[j]*a[1].pri+p;
}
for(i=2;i<=top;i++)
{
cur^=1;
d[cur][0]=0;
for(j=1;j<=m;j++)
{
if(a[i].siz>=b[j].siz)
{
q=d[cur^1][c[i]-1]+(sum[j]-sum[c[i]-1])*a[i].pri+p;
d[cur][j]=d[cur^1][j]>q?q:d[cur^1][j];
}
else
{
d[cur][j]=d[cur^1][j];
}
}
}
printf("case %d: %lld\n",qi,d[cur][m]);
}
scanf("%d%d%d",&p,&n,&m);
}
return 0;
}
int Cmpa(const Pac*i,const Pac*j)
{
return (*i).siz==(*j).siz?(*i).pri-(*j).pri:(*j).siz-(*i).siz;
}
int Cmpb(const Box*i,const Box*j)
{
return (*j).siz-(*i).siz;
}