uva 10280 Old Wine Into New Bottles

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tengfei461807914/article/details/81781544

原题:
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 input begins with a single positive integer on a line by itself indicating the number of the cases following, each of them as described below. This line is followed by a blank line, and there is also a blank line between two consecutive inputs.
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.
Output
For each test case, the output must follow the description below. The outputs of two consecutive cases will be separated by a blank line. Your output should consist of a single integer: the amount of wine, in ml, that cannot be bottled.

Sample Input
2
10 2
4450 4500
725 750
10000 2
4450 4500
725 750

Sample Output
250
0

中文:

给你一个数n表示有多少酒,范围在1到1000000000。
然后给你m个瓶子,每个瓶子装酒量的范围是l[i]到r[i],每个瓶子有无数个,问你用这m个瓶子最多能装下多少酒。
r[i]范围在325到4500,l[i]的范围不小于r[i]的百分之95,不大于r[i]的百分之99

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=1e18;

const int maxn=101;


int n,m;
int l[maxn],r[maxn];

int dp[450001],cost[4501],vis[4501];

int main()
{
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        n*=1000;
        int res=INT_MAX;
        int flag=1;
        for(int i=1;i<=m;i++)
        {
            cin>>l[i]>>r[i];
            if(n>=l[i]&&n<=r[i])
                flag=0;
            res=min(res,l[i]*l[i]/(r[i]-l[i]));
        }
        if(n>=res||flag==0)
        {
            cout<<0<<endl;
            if(t)
                cout<<endl;
            continue;
        }
        memset(cost,0,sizeof(cost));
        memset(dp,0,sizeof(dp));
        memset(vis,0,sizeof(vis));
        int ind=0;
        for(int i=1;i<=m;i++)
        {
            for(int j=l[i];j<=r[i];j++)
            {
                if(!vis[j])
                {
                    vis[j]=1;
                    cost[++ind]=j;
                }
            }
        }

        for(int i=1;i<=ind;i++)
        {
            for(int j=cost[i];j<=n;j++)
                dp[j]=max(dp[j],dp[j-cost[i]]+cost[i]);
        }
        cout<<n-dp[n]<<endl;
        if(t)
            cout<<endl;
    }
    return 0;
}


解答:

刚看到这题的时候以为很简单的完全背包,仔细一看数据傻眼了,容量太大,没法表示啊?
想着想着就想到网络流去了,结果没弄出来。

看到别人的题解,发现好巧妙的优化方式

设min为瓶子的最小装酒量,max为最大装酒量,那么第k个瓶子

对于一类瓶子,我们不妨设用k个瓶子去装酒,那么能够完全装下的范围就是 [ k m i n , k m a x ] ,随着k的增大,我们发现所有相邻区间的左端点的间距是固定的,同时区间的长度又在不断增加,于是我们猜想,到某一刻时,后面的区间相互之间会有交集,这样剩下的各个区间就会覆盖掉后面所有的整数。我们设刚开始产生交集的区间为第k个,这样有 k m a x >= ( k + 1 ) m i n ,解得 k >= m i n / ( m a x m i n ) ,而当酒量 x >= k m i n 的时候,就一定能全被装进去,这样就有 x >= m i n m i n / ( m a x m i n )

剩下的酒量直接用完全背包就能解决了

参考博客
http://www.cnblogs.com/staginner/archive/2011/12/07/2279783.html

猜你喜欢

转载自blog.csdn.net/tengfei461807914/article/details/81781544
old