金明的预算方案 NOIP 2006提高组 分组背包

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了金明的预算方案 NOIP 2006提高组 分组背包相关的知识,希望对你有一定的参考价值。

题目链接

题意理解:

  • 买附件必须买其对应的主件,因为附件和主件是配套使用的
  • 每个主件对应有n个附件的话,那么对于该主件就有 2 n 2^n 2n种选择

思路:

首先是存储相关的数据,都用pair进行存储体积和价值,然后对于主件对应的附件的个数不定,所以就用vector进行存储。

对于每个主件来说,买的情况下对应有 2 n 2^n 2n种情况选择(n是主件对应附件的个数),如何枚举这些情况呢?就需要利用二进制的思想。对每个数(范围为0到2的n次方)的每一位进行判断,然后求出新的钱数和价值。

  • 最终可以转化为分组背包的问题
#include<bits/stdc++.h>
#define fi first
#define se second

using namespace std;
typedef pair<int ,int > pii;
const int M = 32005,N = 65;

int f[M];
pii master[N];//存储主件的信息
vector<pii>servant[N];//存储主件对应的附件的信息
int n,m;

int main()
{
    cin>>m>>n;
    for(int i=1;i<=n;i++)
    {
        int v,w,q;
        cin>>v>>w>>q;
        if(!q) master[i]={v,v*w};
        else servant[q].push_back({v,v*w});
    }
    for(int i=1;i<=n;i++)
    {
        if(master[i].fi)//如果是主件的话
        {
            for(int j=m;j>=0;j--)//对钱数进行枚举
            {
                auto &sv = servant[i];
                //二进制枚举 主件对应的选择方案
                for(int k=0;k<(1<<sv.size());k++)
                {
                    int v = master[i].fi,w = master[i].se;
                    for(int u=0;u<sv.size();u++)//移动的位数进行枚举
                    {
                        if(k>>u & 1)//当前位是1的话
                        {
                            v += sv[u].fi;
                            w += sv[u].se;
                        }
                    }
                    if(j>=v)//对每个方案进行更新
                        f[j] = max(f[j],f[j-v]+w); 
                }
            }
        }
    }
    cout<<f[m]<<'\\n';
    return 0;
}

以上是关于金明的预算方案 NOIP 2006提高组 分组背包的主要内容,如果未能解决你的问题,请参考以下文章

NOIP提高组2006-金明的预算方案

noip2006 金明的预算方案

P1064 [NOIP2006 提高组] 金明的预算方案

[NOIP2006] 提高组 洛谷P1064 金明的预算方案

[NOIP提高组]金明的预算方案

NOIP2006 金明的预算方案