NOIP2006提高组第二题-金明的预算方案

题意:背包问题,每个物品有价值和所谓的重要度,以及可以是其他物品的附件,只有购买了主件才能购买附件,.求有n元买m件以内的物品的最大价值和重要度乘积的和.其中一个主件的附件数比较少,最多只有2个附件.

分析:数据范围比较小,最多只有2个附件直接分组背包,m件是典型二维费用背包,注意枚举顺序是先分组再枚举二个维度最后再枚举组内的物品.

附上自己乱写的常数大的一批的丑b代码:

  1 #pragma GCC optimize(2)
  2 #include <cstdio>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <vector>
  7 #include <map>
  8 #include <set>
  9 #include <queue>
 10 #include <deque>
 11 #include <list>
 12 #include <climits>
 13 #include <bitset>
 14 #include <fstream>
 15 #include <algorithm>
 16 #include <functional>
 17 #include <stack>
 18 #include <string>
 19 #include <cmath>
 20 #define fi first
 21 #define se second
 22 #define re register
 23 #define ls i << 1
 24 #define rs i << 1 | 1
 25 #define pb push_back
 26 #define mp make_pair
 27 #define pii pair<int,int>
 28 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 29 #define mod 1000000007
 30 
 31 //#define int long long
 32 
 33 using namespace std;
 34 const double eps = 1e-8;
 35 const int inf = 0x3f3f3f3f;
 36 const long long INF = 0x3f3f3f3f3f3f3f3f;
 37 const double pi = acos(-1.0);
 38 
 39 inline int rd(){
 40     re int res = 0,flag = 0;char ch;
 41     if ((ch = getchar()) == '-')flag = 1;
 42      else if(ch >= '0' && ch <= '9')res = ch - '0';
 43     while ((ch = getchar()) >= '0' && ch <= '9')res = (res<<1) + (res<<3) + (ch - '0');
 44     return flag ? -res : res;
 45 }
 46 
 47 void out(int a) {
 48     if (a < 0) {
 49         putchar('-');a = -a;
 50     }
 51     if (a >= 10) out(a / 10);
 52     putchar(a % 10 + '0');
 53 }
 54 
 55 const int maxn = 4e4+10;
 56 const int maxm = 100;
 57 int n, m;
 58 int f[maxn][maxm];
 59 
 60 struct thing{
 61     int val, v, m, id, q;
 62     bool friend operator<(const thing &a, const thing &b) {
 63         return a.q < b.q;
 64     }
 65 };
 66 
 67 vector<thing> goods,e[maxm];
 68 
 69 //二维费用: 1.价值  2.数量
 70 //求最大收益: 价值 * 重要度
 71 
 72 //signed main(){
 73 int main() {
 74     n = rd(), m = rd();
 75     for (int i = 1; i <= m; i++) {
 76         int v = rd(), p = rd(), q = rd();
 77         goods.pb({v*p, v, 1, i, q});
 78     }
 79     sort(goods.begin(), goods.end());
 80     for (int i = 0; i < goods.size(); i++) {
 81         if (goods[i].q == 0) e[goods[i].id].pb({goods[i].val, goods[i].v, 1});
 82         else {
 83             int now = goods[i].q;
 84             int len = e[now].size();
 85             for (int j = 0; j < len; j++) {
 86                 e[now].pb({e[now][j].val + goods[i].val, e[now][j].v + goods[i].v, e[now][j].m + 1});
 87             }
 88         }
 89     }
 90     for (int i = 1; i <= m; i++) {//分组 
 91         if (e[i].size() == 0) continue;
 92             for (int k = n; k >= 0; k--) {//第一维费用 
 93                 for (int j = m; j >= 0; j--) {//第二维费用 
 94                     for (int s = 0; s < e[i].size(); s++) //枚举组内物品 
 95                     if (k >= e[i][s].v && j >= e[i][s].m)
 96                     f[k][j] = max(f[k][j], f[k-e[i][s].v][j-e[i][s].m] + e[i][s].val);
 97                 }
 98             }
 99     }
100     out(f[n][m]);
101     return 0;
102 }

 积累:

   yxc:所有的背包问题都是先循环物品再循环体积再循环决策.

posted @ 2020-07-04 21:29  Kimyon  阅读(204)  评论(0编辑  收藏  举报