HDU-2546 饭卡 题解 | ACM

原文链接:HDU-2546 饭卡 题解 | ACM
个人博客网站:FengLinger | 小世界
###首先这是一道典型的01背包问题

题目描述电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
输入数据多组数据。对于每组数据:第一行为正整数n,表示菜的数量。n<=1000。第二行包括n个正整数,表示每种菜的价格。价格不超过50。第三行包括一个正整数m,表示卡上的余额。m<=1000。n=0表示数据结束。
数据输出对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。
样例1 50 5 10 1 2 3 2 1 1 2 3 2 1 50 0
样例输出-45 32

首先放出AC代码:

#include<stdio.h>
#include<math.h>

int max(int a,int b);
void px(int *a);

int main()
{
	int card,n;
	while(~scanf("%d",&n),n)
	{
	int dishes[1012] = {0};
	int zeroOne[1012] = {0};
		for(int i = 0;i < n;i++)
		{
			scanf("%d",&dishes[i]);
		}
		scanf("%d",&card);
		if(card < 5)
		{
			printf("%d\n",card);
			continue;
		}
		card -= 5;
		px(dishes);


  		for(int i = 0; i < n-1 ;i++)
		{

			if(dishes[i] == 0)
				break;
			for(int j = card;j >= dishes[i];j--)
			{
				zeroOne[j] = max(zeroOne[j],zeroOne[j-dishes[i]]+dishes[i]);
			}
		}
		printf("%d\n",(card+5-zeroOne[card]-dishes[n-1]));
	}

	return 0;
}

void px(int *a)
{
	int i,j;
	int temp;
	for(i = 0;i < 1012;i++)
	{
		if(a[i]==0)
			continue;
		temp = a[i];
		j = i-1;
		while(j>=0&&a[j] > temp)
		{
			a[j+1] = a[j];
			j--;
		}
		a[j+1] = temp;
	}
}

int max(int a,int b)
{
		return a>b?a:b;

}

我认为此题的关键在于以下几点:

  • 01背包算法
  • 卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负)否则无法购买(即使金额足够)

所以在代码里面,我将输入情况分为金额少于5元和多于5元两种情况。

  • 金额少于5元:
if(card < 5)
{
	printf("%d\n",card);
	continue;
}
  • 金额多于5元
card -= 5;
px(dishes);


for(int i = 0; i < n-1 ;i++)
{

	if(dishes[i] == 0)
		break;
	for(int j = card;j >= dishes[i];j--)
	{
		zeroOne[j] = max(zeroOne[j],zeroOne[j-dishes[i]]+dishes[i]);
	}
}

当金额多于5元时,先将这5元保留,以便最后去买最贵的菜。
用减去5元之后的余下金额去做01背包
在这里,我最一开始按照我查资料得到的二维数组的方法,写出如下代码(因为存在仍然理解不透彻的原因,可能有错):

for(int i = 0;i < count;i++ )
{
	for(int j = 0;j <= card;j++)
	{
		zeroOne[i][j] = max(zeroOne[i-1][j],zeroOne[i][j-dishes[i-1]]+dishes[i-1])
	}
}

由于还是理解不透彻,于是上网查找有关本题的滚动数组优化代码:

for(int j = card;j >= dishes[i];j--)
{
	zeroOne[j] = max(zeroOne[j],zeroOne[j-dishes[i]]+dishes[i]);
}

我觉得这个好想要更好理解一点?
其中变量zeroOne中存放的是已经花掉的金额

最后输出的时候,最终结果为:卡里面最初的总金额 - 已经花掉的金额 - 最贵那道菜的金额。

printf("%d\n",(card+5-zeroOne[card]-dishes[n-1]));
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值