UVA 10645-Menu(DP)

题目大意:Alfred要准备一些菜,每天一道菜,每个菜有收益和花费,如果连续两天准备同一道菜,收益减半,连续三天或更多,则不获得好感值,求在预算内的最多收益并输出每一天准备的菜。如果多个情况能获得相同的收益,输出花费较少的,如果还有多个,随意输出。


用d[i][j][u][0]表示前i天,花费至少j,第i天为第u道菜且第i-1天不为第u道菜时,最大的收益,

用d[i][j][u][1]表示前i天,花费至少j,第i天为第u道菜且第i-1天为第u道菜时,最大的收益。

a[u].cost和a[u].ben表示第u道菜的花费和收益。


对于d[i][j][u][0],由于它的前一天的菜不是u,所以找到前一天花费不超过j-a[u].cost,且最后一道菜(也就是第i-1天的菜)不是u时的最大收益是多少,就可以完成递推。

实际上只需要存储最大的3个收益值的信息(原因是3个中必然有一个的第i-1天的菜不和u相同)。在程序中用max[j][0],max[j][1],max[j][2]分别表示第一大,第二大,第三大收益值时的信息(当然也可以遍历一遍i-1天的情况,但这样复杂度升高)。max的第一维不用保存,每次运算完前两维时更新max数组。

对于d[i][j][u][1],它的前一天的菜是u,就由d[i-1][j-a[u].cost][u][0]或d[i-1][j-a[u].cost][u][1]递推而来。


程序将收益值乘2,在运算过程中避免浮点运算。

总体复杂度为O(n*m*k)


#include<stdio.h>
#include<stdlib.h>
typedef struct
{
	int cost;
	int ben;
}Coo;
typedef struct
{
	int num;
	int rep;
	int ben;
}Maxt;
Coo a[110];
int b[110];
Maxt max[110][3];
int d[25][110][55][2];
int pre[25][110][55][2][2];
int main(void)
{
	int i,j,u,v,p,q,n,m,uu,vv,pp,qq,ans,min;
	scanf("%d%d%d",&n,&m,&p);
	while((n!=0)||(m!=0)||(p!=0))
	{
		min=(1<<30);
		for(i=1;i<=m;i++)
		{
			scanf("%d%d",&u,&v);
			a[i].cost=u;
			a[i].ben=v*2;
			min=(u<min)?u:min;
		}
		if(min*n>p)
		{
			printf("0.0\n");
		}
		else if(m==1)
		{
			ans=a[1].ben+a[1].ben/2;
			printf("%d.%d\n",ans/2,ans%2==0?0:5);
			printf("1");
			for(i=2;i<=n;i++)
			{
				printf(" 1");
			}
			printf("\n");
		}
		else
		{
			for(j=1;j<=p;j++)
			{
				max[j][0].ben=max[j][1].ben=max[j][2].ben=-(1<<30);
				for(u=1;u<=m;u++)
				{
					v=j-a[u].cost;
					d[1][j][u][1]=-(1<<30);
					if(v<0)
					{
						d[1][j][u][0]=-(1<<30);
					}
					else
					{
						d[1][j][u][0]=a[u].ben;
					}
					if(d[1][j][u][0]>max[j][0].ben)
					{
						max[j][2]=max[j][1];
						max[j][1]=max[j][0];
						max[j][0].ben=d[1][j][u][0];
						max[j][0].rep=0;
						max[j][0].num=u;
					}
					else if(d[1][j][u][0]>max[j][1].ben)
					{
						max[j][2]=max[j][1];
						max[j][1].ben=d[1][j][u][0];
						max[j][1].rep=0;
						max[j][1].num=u;
					}
					else if(d[1][j][u][0]>max[j][2].ben)
					{
						max[j][2].ben=d[1][j][u][0];
						max[j][2].rep=0;
						max[j][2].num=u;
					}
				}
			}
			for(i=2;i<=n;i++)
			{
				for(j=1;j<=p;j++)
				{
					for(u=1;u<=m;u++)
					{
						v=j-a[u].cost;
						if(v<=0)
						{
							d[i][j][u][0]=d[i][j][u][1]=-(1<<30);
						}
						else
						{
							if(max[v][0].num!=u)
							{
								d[i][j][u][0]=max[v][0].ben+a[u].ben;
								pre[i][j][u][0][0]=max[v][0].num;
								pre[i][j][u][0][1]=max[v][0].rep;
							}
							else if(max[v][1].num!=u)
							{
								d[i][j][u][0]=max[v][1].ben+a[u].ben;
								pre[i][j][u][0][0]=max[v][1].num;
								pre[i][j][u][0][1]=max[v][1].rep;
							}
							else
							{
								d[i][j][u][0]=max[v][2].ben+a[u].ben;
								pre[i][j][u][0][0]=max[v][2].num;
								pre[i][j][u][0][1]=max[v][2].rep;
							}
							if(d[i-1][v][u][0]+a[u].ben/2>d[i-1][v][u][1])
							{
								d[i][j][u][1]=d[i-1][v][u][0]+a[u].ben/2;
								pre[i][j][u][1][0]=u;
								pre[i][j][u][1][1]=0;
							}
							else
							{
								d[i][j][u][1]=d[i-1][v][u][1];
								pre[i][j][u][1][0]=u;
								pre[i][j][u][1][1]=1;
							}
						}
					}
				}
				for(j=1;j<=p;j++)
				{
					max[j][0].ben=max[j][1].ben=max[j][2].ben=-(1<<30);
					for(u=1;u<=m;u++)
					{
						if(d[i][j][u][0]>max[j][0].ben)
						{
							max[j][2]=max[j][1];
							max[j][1]=max[j][0];
							max[j][0].ben=d[i][j][u][0];
							max[j][0].rep=0;
							max[j][0].num=u;
						}
						else if(d[i][j][u][0]>max[j][1].ben)
						{
							max[j][2]=max[j][1];
							max[j][1].ben=d[i][j][u][0];
							max[j][1].rep=0;
							max[j][1].num=u;
						}
						else if(d[i][j][u][0]>max[j][2].ben)
						{
							max[j][2].ben=d[i][j][u][0];
							max[j][2].rep=0;
							max[j][2].num=u;
						}
						if(d[i][j][u][1]>max[j][0].ben)
						{
							max[j][2]=max[j][1];
							max[j][1]=max[j][0];
							max[j][0].ben=d[i][j][u][1];
							max[j][0].rep=1;
							max[j][0].num=u;
						}
						else if(d[i][j][u][1]>max[j][1].ben)
						{
							max[j][2]=max[j][1];
							max[j][1].ben=d[i][j][u][1];
							max[j][1].rep=1;
							max[j][1].num=u;
						}
						else if(d[i][j][u][1]>max[j][2].ben)
						{
							max[j][2].ben=d[i][j][u][1];
							max[j][2].rep=1;
							max[j][2].num=u;
						}
					}
				}
			}
			ans=-(1<<30);
			for(j=1;j<=p;j++)
			{
				for(u=1;u<=m;u++)
				{
					if(d[n][j][u][0]>ans)
					{
						uu=u;
						vv=0;
						q=j;
						ans=d[n][j][u][0];
					}
					if(d[n][j][u][1]>ans)
					{
						uu=u;
						vv=1;
						q=j;
						ans=d[n][j][u][1];
					}
				}
			}
			for(i=n;i>=1;i--)
			{
				b[i]=uu;
				pp=pre[i][q][uu][vv][0];
				qq=pre[i][q][uu][vv][1];
				u=q-a[uu].cost;
				uu=pp;
				vv=qq;
				q=u;
			}
			printf("%d.%d\n",ans/2,ans%2==0?0:5);
			printf("%d",b[1]);
			for(i=2;i<=n;i++)
			{
				printf(" %d",b[i]);
			}
			printf("\n");
		}
		scanf("%d%d%d",&n,&m,&p);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值