(中等)动态规划 HOJ 1770 Old Wine Into New Bottles

Old Wine Into New Bottles

My Tags  (Edit)
Source : Waterloo ACM Programming Contest Oct 2, 1999
Time limit : 1 secMemory limit : 32 M

Submitted : 108, Accepted : 35

(中等)动态规划 HOJ 1770 Old Wine Into New Bottles - 恶魔仁 - 恶魔仁Wine bottles are never completely filled: a small amount of air must be left in the neck to allow for thermal expansion and contraction. If too little air is left in the bottle, the wine may expand and expel the cork; if too much air is left in the bottle, the wine may spoil. Thus each bottle has a minimum and maximum capacity.

Given a certain amount of wine and a selection of bottles of various sizes, determine which bottles to use so that each is filled to between its minimum and maximum capacity and so that as much wine as possible is bottled.


Input

The first line of input contains two integers: the amount of wine to be bottled (in litres, between 0 and 1,000,000) and the number of sizes of bottles (between 1 and 100). For each size of bottle, one line of input follows giving the minimum and maximum capacity of each bottle in millilitres. The maximum capacity is not less than 325 ml and does not exceed 4500 ml. The minimum capacity is not less than 95% and not greater than 99% of the maximum capacity. You may assume that an unlimited number of each bottle is available.

Input contains multiple test cases. Process to the end of file.


Output

Your output should consist of a single integer: the amount of wine, in ml, that cannot be bottled.

Sample Input

10 2
4450 4500
725 750
10000 2
4450 4500
725 750
Sample Output
250
0

题意:给出一个酒的容量,然后给出一系列瓶子的容量范围,求最少有多少酒装不进酒瓶
思路:这题显然是一个背包问题,但是背包的容量太大了,这题目中是10^9 所以要先用贪心,把他降到10^6  然后将各个酒瓶的范围内的容量都分出来作为一个物品,最多会有4500-325+325*0.05~=4192
另外还能做一个小小的优化,就是如果酒的数量能被某一个物品的价值整除,那么显然应该输出0 

代码:
#include<iostream>
#include<string.h>
#include<cstdio>
#include<stdio.h>
#include<map>
#include<vector>
using namespace std;
#define MAX 100+10
#define MOD 100000000
const int inf = 0x7fffffff;
int min_cap[MAX];
int max_cap[MAX];
int dp[1000010];
int item[4510];
bool in_item[4510];

inline int max(int x,int y)
{
return x > y ? x : y;
}

int main()
{
int V,n;
while (scanf("%d%d",&V,&n)==2)
{
int sz = 0;
memset(in_item,false,sizeof(in_item));
int tem_min = inf;
V *= 1000;
bool ok = false;
if (V==0) ok = true;
for (int i = 1 ; i <= n ; ++i)
{
scanf("%d%d",min_cap+i,max_cap+i);
if (ok) continue;
tem_min = min(min_cap[i],tem_min);
for (int j = min_cap[i] ; j <= max_cap[i] ; ++j)
{
if (V%j==0) 
{
ok = true;
break;
}
if (!in_item[j])
{
item[sz++] = j;
in_item[j] = true;
}
}
}
if (ok)
{
printf("0\n");
continue;
}
memset(dp,0,sizeof(dp));
if (V>1000000) V = V-tem_min*(1+(V-1000000)/tem_min);
for (int i = 0 ; i < sz ; ++i)
{
int w = item[i];
for (int j = w ; j <= V ; ++j) if (dp[j-w]+w>dp[j])
dp[j] = dp[j-w]+w;
}
printf("%d\n",V-dp[V]);
}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值