金明的预算方案 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提高组 分组背包的主要内容,如果未能解决你的问题,请参考以下文章