zoukankan      html  css  js  c++  java
  • 多重背包 /// 单调队列DP oj1943

    题目大意:

    em.... 就是多重背包

    挑战340页的东西 ...自己的笔记总结总是比较乱的

    重点:原始的状态转移方程中 更新第 i 种物品时 重量%w[i] 的值不同 则它们之间是相互独立的;

    1--- 就是说在考虑第 i 种物品拿几个时,w[i]+1 与 2*w[i]+1 与...与 k*w[i]+1 相互之间是有关联的

      但 w[i]+j ... k*w[i]+j (j不为1) 与 w[i]+1 是相互独立 无关的,即%w[i]的值不同时 相互独立

    2--- 那么可以将 w[i]+j 与 2*w[i]+j 与...与 k*w[i]+j 的最优解都压在 j 中,因为只要知道 j 的最优解

      并且知道 k(个数),就知道 k*w[i]+j的最优解 = j的最优解 + k*v[i]

    用双端队列维护不同余数 j 的最优解,采用题目 滑动最小值 的方法维护 m[i]个物品在不同重量区间 的最大值

    #include <bits/stdc++.h>
    using namespace std;
    int n,W,w[10005],v[10005],m[10005],dp[10005];
    int deq[10005],deqv[10005]; // 模拟deque deq保存下标 deqv保存值
    int main()
    {
        int t;
        while(~scanf("%d",&t)) {
            while(t--) {
                scanf("%d%d",&n,&W);
                for(int i=0;i<n;i++)
                    scanf("%d%d%d",&w[i],&v[i],&m[i]);
                memset(dp,0,sizeof(dp));
                for(int i=0;i<n;i++) // 第i种物品
                    for(int j=0;j<w[i];j++) { // 枚举不同余数
                        int head=0, tail=0;
                        /// 双端队列维护余数为 j 时的最优解
                        // 则每个 j 开始时都应该赋0清空队列
                        
                        for(int k=0;k*w[i]+j<=W;k++) { // 枚举该物品个数
                            int nowv=dp[k*w[i]+j]-k*v[i]; 
                            /// 原本重量为 k*w[i]+j 的最优解
                            // 可能其他种物品有更新过该重量的最优解
                            /// 压到 j 时对应的最优解
                            
                            while(head<tail && deqv[tail-1]<=nowv) tail--; 
                            /// 与曾中出现过存放在队列中的最优解比较
                             
                            deq[tail]=k, deqv[tail++]=nowv; // 更新队列 队头head对应的即为最优解
                            dp[k*w[i]+j]=deqv[head]+k*v[i]; // 更新dp[]保存的最优解
                            
                            if(deq[head]==k-m[i]) head++; 
                            /// 如果head对应的已经是m[i]个中的第一个 
                            /// 即到下一个时 head对应的物品数量会超出m[i]的限制
                            /// 则应该舍弃这个最优解 把队头head移向下一位
                        }
                    }
                printf("%d
    ",dp[W]);
            }
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    oracle 增加列
    20120621 myeclipse 远程调试
    plsql 参数中in out in的区别讲解
    20120606 随笔
    MYSQL申明变量&显示变量
    arcgis for flex 地图发布服务
    arcserver 地图发布过程
    arcserver 发布地图后浏览器不更新问题
    把一个表的一列插入另一个表的空字段
    mysql运行语句时出现 FUNCTION *** does not exist
  • 原文地址:https://www.cnblogs.com/zquzjx/p/9153715.html
Copyright © 2011-2022 走看看