美文网首页动态规划
背包九讲01-关于常数的优化

背包九讲01-关于常数的优化

作者: ColdRomantic | 来源:发表于2016-08-28 01:13 被阅读258次

    01背包容量为V,在求能装入物品的获得最大价值dp[V]时,有一个常数优化。(也适用于恰好装满容量为V的01背包问题)
    说明:大写字母V表示背包的容量。

    关于一个常数优化的问题

    前提:如果我们最后只想计算出dp[V]的值,根据动归方程:

     dp[v]=max(dp[v],dp[v-ci]+wi);//i表示第i个物品
    

    1 当计算到第n个物品时,我们只需要知道dp[V-cn]的值是多少,也就是说计算第n-1个物品的时候我们只需要计算出dp[V-cn]的值就可以停止循环了。进一步,当处理第i个物品时只需要循环到:

    备注:原作者手误把公式中ci+1写成了wi。
    2 在上一步的优化下,我们发现先处理花费较大的物品会使得后续物品的循环次数更少,所以我们还可以做一个优化:把物品按照花费从大到小排序。
    最后:基于上面两步优化,我在网上找个题目(nyoj654)来验证下正确性,运行结果如下。

    运行结果 耗时排名

    代码如下:

    /** nyoj: 654*/
    //c header
    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    //cpp header
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <string>
    
    using namespace std;
    #define M 1100000 //Max bag's Capacity
    #define N 120 //Max Item's amount
    #define CLS(x,v) memset(x,v,sizeof(x))
    typedef pair<int,int> ppi;
    
    /**Cap is the bag's Capacity; SumCost is the sum of Item's cost*/
    int dp[M],Cap,SumCost;
    /** first is cost ,second is weight*/
    int cmp(ppi x,ppi y)
    {
        //return true will be Swap elements
        return x.first>y.first;
    }
    int ZeroOnePack(int cost,int weight)
    {
        SumCost-=cost;
        int bound=max(Cap-SumCost,cost);
        for(int v=Cap;v>=bound;--v)
            dp[v]=max(dp[v],dp[v-cost]+weight);
    }
    int solve(vector<ppi> &Items)
    {
        CLS(dp,0);
        for(int i=0;i<Items.size();i++)
            ZeroOnePack(Items[i].first,Items[i].second);
        //return Answer
        return dp[Cap];
    }
    
    int main()
    {
        int T,n,cost,weight;
        vector<ppi>Items;
        //large input take effect obviously
        ios::sync_with_stdio(false);
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&Cap);
            SumCost=0;
            Items.clear();
            for(int i=0;i<n;i++)
            {
                scanf("%d%d",&cost,&weight);
                SumCost+=cost;
                Items.push_back(make_pair(cost,weight));
            }
            sort(Items.begin(),Items.end(),cmp);
            printf("Max experience: %d\n",solve(Items));
        }
        return 0;
    }
    

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=654

    相关文章

      网友评论

      • migeater:1 当计算到第n个物品时,我们只需要知道dp[V-cn]的值是多少,也就是说计算第n-1个物品的时候我们只需要计算出dp[V-cn]的值就可以停止循环
        楼主这里排版没弄好
      • 7dd194413303:常数优化那里。。我也觉得下标是从i+1开始,然而原作上下标是从i开始的,网上搜了半天都是从i开始的,搞得我怀疑人生。。
        ColdRomantic:@7dd194413303 可以给原作者PR,我感觉应该是手误。

      本文标题:背包九讲01-关于常数的优化

      本文链接:https://www.haomeiwen.com/subject/yrutettx.html