UVA 11252-Take Me Home (To the Place I Belong)(DP)

题目大意:有几种包裹需要打包,每种包括有一定的体积,每种包裹可能有多个。有一个运输公司提供了多种包裹服务,每种有一定的尺寸和价格,多加一种服务需要多付一定数量的钱。为了节省掉这一部分的钱,小的包裹可以使用大尺寸来运输,但大的不能用小的来运输,求最小价格。


首先对服务排序,根据尺寸从大到小排序,如果有某些服务相对于某个其他的服务,尺寸小价格反而贵,则这种服务直接舍去。

然后对包裹按尺寸从大到小排序。


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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值