UVa 10280 Old Wine Into New Bottles(剪枝+完全背包)

题意:

给L升酒,有n个酒瓶,每个酒瓶有个最大容量和最小容量,酒瓶的个数不限。

问最多剩多少毫升酒没有装进去。

思路:

http://www.cnblogs.com/staginner/archive/2011/12/07/2279783.html

这一题用到了一个优化的剪枝,另外上面博客对于物品的处理也是非常得当。

做完题目之后如沐清风,回味无穷。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <algorithm>
using namespace std;

const int MAXL = 450000;
const int MAXD = 4600;
const int MAXN = 110;

int dp[MAXL], v[MAXD];
bool vis[MAXD];
int cmax[MAXN], cmin[MAXN];
int L, n;

int solve()
{
    int limit = INT_MAX;
    for (int i = 0; i < n; ++i)
        limit = min(limit, cmin[i]*cmin[i]/(cmax[i]-cmin[i]));
    if (limit < L)
        return 0;

    int m = 0;
    memset(vis, false, sizeof(vis));
    for (int i = 0; i < n; ++i)
        for (int j = cmin[i]; j <= cmax[i]; ++j)
            if (!vis[j])
                vis[j] = true, v[m++] = j;

    memset(dp, 0, sizeof(dp));
    for (int i = 0; i < m; ++i)
        for (int j = v[i]; j <= L; ++j)
            dp[j] = max(dp[j], dp[j-v[i]] + v[i]);

    return L - dp[L];
}

int main()
{
    int cases;
    scanf("%d", &cases);
    while (cases--)
    {
        scanf("%d %d", &L, &n);
        L *= 1000;
        for (int i = 0; i < n; ++i)
            scanf("%d %d", &cmin[i], &cmax[i]);

        printf("%d\n", solve());
        if (cases)
            printf("\n");
    }
    return 0;
}

 

posted @ 2012-11-27 16:15  kedebug  阅读(397)  评论(0编辑  收藏  举报