zoukankan      html  css  js  c++  java
  • 背包

     

     

     

      1 #include <cmath>
      2 #include <cstdio>
      3 #include <cstdlib>
      4 #include <iostream>
      5 #include <algorithm>
      6 const int MAXN = 100;
      7 const int MAXV = 200000;
      8 using namespace std;
      9 
     10 int n, V;
     11 int num[MAXN + 10], volume[MAXN + 10], value[MAXN + 10];//
     12 
     13 long long f_arr[MAXV + 10];//数组而已,只不过用指针来表示 这个是完全背包滚动数组 
     14 long long g_arr[MAXV + 10];// 
     15 long long *f = f_arr;//
     16 long long *g = g_arr;//
     17 
     18 int fr_arr[MAXV + 10], nfr_arr[MAXV + 10];//意义不明猜测记录路径 
     19 int *fr = fr_arr;
     20 int *nfr = nfr_arr;
     21 
     22 int q[MAXV + 10];//记录当前物品选择个数的数组 
     23 
     24 int vis[MAXV + 10];//记录是否访问过 
     25 int Y;//懒标 
     26 
     27 long long ans = 0;//最大价值 
     28 int ans_r[MAXN + 10];//路径 不明如何计算 
     29 
     30 void dp(int l, int r, int s, int t) {
     31     if (r - l == 1)//当只有一种可以枚举 ,不能再找中点 
     32         return;
     33 
     34     int mid = (l + r + 1) >> 1; // r - l = 1, choose r, correctness trick (not used in this prob)洋屁看不懂,大概意思是在r-l=1的情况下选择r,是一个技巧(但在这段代码里没有使用) 
     35 
     36     f[s] = 0, fr[s] = -1, vis[s] = ++Y;//vis懒标  <-- 
     37     for (int i = l+1; i <= r; ++i) {//枚举第一个物品 
     38         for (int j = 0; j < volume[i]; ++j) {//当前容积 
     39             if (s + j > t) //超出当前背包容积 
     40                 break;
     41             int maxk = (t - (s + j)) / volume[i]; 
     42             int ht = 1, qt = 0;//头和尾存当前这个物品放的个数 
     43             int pos = s + j;//放了当前物品的体积 
     44             for (int k = 0; k <= maxk; ++k) {//完全背包模板 
     45                 while (ht <= qt && k - q[ht] > num[i])
     46                     ++ht;
     47 
     48                 if (vis[pos] == Y) {//如果作为起点访问过  当前q栈里存的方案不够好弹出 
     49                     while (ht <= qt && f[q[qt] * volume[i] + j + s] + (long long) value[i] * (k - q[qt]) <= f[pos])
     50                         --qt;
     51 
     52                     q[++qt] = k;//选k个,把较差的情况从q栈中弹出 
     53                 }
     54 
     55                 if (ht <= qt) {//f和g互换 滚动数组 
     56                     g[pos] = f[q[ht] * volume[i] + j + s] + (long long) value[i] * (k - q[ht]);//当前q栈中存的一定是最优的情况 
     57 
     58                     if (i == mid) nfr[pos] = pos;//路径中点,即(n/2,x) 所以这两个fr nfr是拿来存中点的?? <--
     59                     else nfr[pos] = fr[q[ht] * volume[i] + j + s]; 
     60 
     61                     vis[pos] = Y;//懒标,表示现在这个位置来过 
     62                 }
     63                 else 
     64                     g[pos] = 0, nfr[pos] = -1;//当前情况就是q栈中没有数据,即没有更好的方案,但清零并不能理解 
     65 
     66                 pos += volume[i];//当前背包体积加上当前的物品体积进行下一轮计算 
     67             }
     68         }
     69         swap(f, g);//数组滚动 
     70         swap(fr, nfr);
     71     }
     72     
     73     ans_r[mid] = fr[t];//<--记录中点 
     74 
     75     if (l == 0 && r == n) // first dp, save the ans  ans记录完全背包的最大值 
     76         ans = f[t];
     77 
     78     dp(l, mid, s, ans_r[mid]);//开分 
     79     dp(mid, r, ans_r[mid], t); 
     80 }
     81  
     82 int main() {
     83     freopen("knapsack.in", "r", stdin);
     84     freopen("knapsack.out", "w", stdout); 
     85     cin >> n >> V;
     86     for (int i = 1; i <= n; ++i)
     87         cin >> num[i] >> volume[i] >> value[i];//数量 体积 价值 
     88 
     89     reverse(num + 1, num + n + 1);//反转,其实可以从后往前读入 
     90     reverse(volume + 1, volume + n + 1);
     91     reverse(value + 1, value + n + 1);
     92 
     93     ans_r[0] = 0, ans_r[n] = V;//初始化?? 
     94     dp(0, n, 0, V);//dp入口 
     95 
     96     cout << ans << endl;//最大价值 
     97     for (int i = n; i >= 1; --i) {
     98         cout << (ans_r[i] - ans_r[i-1]) / volume[i];//输出路径开始意义不明 
     99 
    100         ans -= (ans_r[i] - ans_r[i-1]) / volume[i] * value[i];//ans到现在没什么软用了吧,可能检验用的 
    101 
    102         if (i != 1)
    103             cout << " ";//输出格式 
    104         else
    105             cout << endl;
    106     }
    107 }
    View Code

  • 相关阅读:
    在下拉框中选择数据
    代码添加批处理类
    重置用户状态(初始化用户)
    当前窗口控制(显示、隐藏、破坏)
    窗体分隔符实现
    使用USB移动硬盘 遭遇 "Windows无法为Volume加载安装程序。请于硬件供应商联系,寻求协助" 错误,“灰鸽子”后遗症的处理
    使用IDL创建TypeLib(.tlb)文件
    ngrep使用方法
    常用的正则表达式
    治疗鼻炎的药
  • 原文地址:https://www.cnblogs.com/lifeisabadword/p/11815576.html
Copyright © 2011-2022 走看看