有依赖的背包 洛谷P1064 金明的预算方案 (不是分组背包)

题意:买附件的前提是买了主件,问给定金额获得的最大价值。

分析:有依赖的背包模板题,注意有依赖的背包不是分组背包的那种三个for的顺序,而是枚举一个主件后,不断的枚举附件,而购买多个不同的附件。

同时,在写法上,用 f 数组表示答案数组,f 的每个 j 都是对应最优的决策,而每次枚举都在 t 数组上操作,再判断f 数组上哪些需要更新。

  *分组背包是将物品分组,每组的物品相互冲突,最多只能选一个物品放进去。其实是从“在所有物品中选择一件”变成了“从当前组中选择一件”,于是就对每一组进行一次 0-1 背包就可以了。

  *分组背包核心代码:

for (int k = 1; k <= ts; k++)          //循环每一组
  for (int i = m; i >= 0; i--)         //循环背包容量
    for (int j = 1; j <= cnt[k]; j++)  //循环该组的每一个物品
      if (i >= w[t[k][j]])
        dp[i] = max(dp[i],
                    dp[i - w[t[k][j]]] + c[t[k][j]]);  //像0-1背包一样状态转移 ,像0-1背包一样的防止重复放进同一物品的思路

本题代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;

const int maxn = 202003;
struct node{
    int p,v,f;
}a[777];
int f[maxn];
int t[maxn];

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++){
        scanf("%d%d%d",&a[i].p,&a[i].v,&a[i].f);
        a[i].v *= a[i].p;
    }
    for(int i=1; i<=m; i++){               //一步
        if(!a[i].f){
            for(int j=0; j<a[i].p; j++){
                t[j] = f[j];
            }
            for(int j=a[i].p; j<=n; j++){
                t[j] = f[j - a[i].p]+a[i].v;
            }
            for(int k=1; k<=m; k++){      //两步
                if(a[k].f==i){
                    for(int j=n; j>=a[i].p; j--){    //三步    (注意这不是多组背包的写法,可以放进同一组的物品)  
                        if(j-a[k].p>=a[i].p){
                            // printf("yes\n");
                            t[j] = max(t[j-a[k].p]+a[k].v , t[j]);
                            // printf("%d %d\n", j, t[j]);
                        }
                    }
                }
            }
            for(int j=a[i].p; j<=n; j++){
                f[j] = max(f[j],t[j]);
            }
        }
    }
    printf("%d\n", f[n]);

}

 

猜你喜欢

转载自www.cnblogs.com/-Zzz-/p/11415839.html