动态规划 HDU 2546 饭卡

        在acm群里看到了这样的一个题目,拿过来看了一下,感觉还蛮有意思的,题目大意是饭卡上有m余额,但是学校有个规定,饭卡余额少于5元就不能买东西,现在有n件商品,每件商品都有一个价格。要求买好商品后余额最少。

        题目链接   HDU 2546 饭卡

        看到题目就想到了背包问题,在一个m-5的背包里尽量装满东西,装满后放最后一个物品,解肯定在放完这个物品之后。 最直接的想法就是对放的最后这个物品进行枚举,然后用余下的物品去装m-5的背包,尽量装满。得到的最小值就是答案。当然还要考虑余额小于5元的情况,如果小于5元就直接输出就行了,因为不能买东西。

        思路有了,接下去是实现,n是1000,m是1000,价格不会超过50,如果枚举的话,复杂度是n*n*m,明显会超时。由于每件商品价格不会超过50,那么只要统计下对应价格的商品件数就行了,然后用二进制优化。

       帖代码:

     

#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0xFFFFFFF
int price[55]; //统计对应价格的商品件数
int dp[1001],m;

void zeroOnePack(int volume)
{
	for (int k=m-5; k>=volume; k--)
	{
		dp[k] = max(dp[k], dp[k-volume]+volume);
	}
}
int main()
{
	int  n, p;
	while (cin >> n && n )
	{
		memset(price, 0, sizeof(price));
		for (int i=0; i<n; i++)
		{
			cin >> p;
			price[p] ++ ;
		}
		cin >> m;
		if (m <5) { cout << m << endl; continue; }

		int ans = INF;
		for (int i=1; i<=50; i++)
		{
			if (!price[i]) continue;
			price[i] --;
			memset(dp, 0, sizeof(dp));
			for (int j=1; j<=50; j++)
			{
				if (!price[j]) continue;

				int total = price[j];
				for (int gs=1 ; total>=gs; gs<=1, total-= gs)
				{
					zeroOnePack(gs*j);
				}
				zeroOnePack(total*j);
			}
			int tmp = m-dp[m-5]-i;
			if (ans > tmp) ans = tmp;
			price[i] ++;
		}

		cout << ans << endl;
	}
}


 

 

你可能感兴趣的:(动态规划,ACM)