487. 金明的预算方案 - AcWing题库
对于每组主件和附件,我们对它们不同的选择方式构成分组背包的一组。比如说某组存在一个主件和一个附件,那么把它转化为分组背包问题,这一组中的元素有①选择主件不选择附件②选择主件和附件③都不选择。
在枚举每一组中的不同元素时,可以采取二进制的方法。
二维代码:
#include
#include
using namespace std;
const int N=32010,M=65;
typedef pair PII;
#define x first
#define y second
int n,m;
PII zhujian[M];
vector fujian[M];
int f[M][N];
int main()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
{
int vv,pp,qq;
scanf("%d%d%d",&vv,&pp,&qq);
if(qq==0) zhujian[i]={vv,pp*vv};
else fujian[qq].push_back({vv,pp*vv});
}
for(int i=1;i<=n;i++)
{
if(zhujian[i].x)
for(int j=0;j<=m;j++)
{
int t=fujian[i].size();
f[i][j]=f[i-1][j];
for(int k=0;k<1<>u&1)
{
v+=fujian[i][u].x;
w+=fujian[i][u].y;
}
}
if(j>=v) f[i][j]=max(f[i][j],f[i-1][j-v]+w);
}
}
else
for(int j=0;j<=m;j++)
f[i][j]=f[i-1][j];
}
printf("%d",f[n][m]);
}
一维代码:
#include
#include
using namespace std;
const int N=32010,M=65;
typedef pair PII;
#define x first
#define y second
int n,m;
PII zhujian[M];
vector fujian[M];
int f[N];
int main()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
{
int vv,pp,qq;
scanf("%d%d%d",&vv,&pp,&qq);
if(qq==0) zhujian[i]={vv,pp*vv};
else fujian[qq].push_back({vv,pp*vv});
}
for(int i=1;i<=n;i++)
{
if(zhujian[i].x)
for(int j=m;j>=0;j--)
{
int t=fujian[i].size();
for(int k=0;k<1<>u&1)
{
v+=fujian[i][u].x;
w+=fujian[i][u].y;
}
}
if(j>=v) f[j]=max(f[j],f[j-v]+w);
}
}
}
printf("%d",f[m]);
}
532. 货币系统 - AcWing题库
这道题有一个性质,b是a的子集,因为如果bn不属于a,由于a和b是等价的,则就可以用任意的a表示出bn,也就可以用任意的b表示出bn,此时的bn就没必要存在在b中了。
因此,我们只需要对a中的元素进行决策,决策的依据是当前元素是否能被a中的其他元素凑出,如果能被凑出,则当前元素无效,不能被凑出则有效。
判断元素能否被凑出,等效于判断当有n个可以无限次选择的元素时,当前元素是否能被凑出,其实就是一个完全背包的操作。
#include
#include
#include
using namespace std;
const int N=25010;
int T;
int f[N];
int main()
{
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
int a[N];
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
memset(f,0,sizeof(f));
f[0]=1;
int cnt=0;
for(int i=1;i<=n;i++)
{
if(f[a[i]]==0) cnt++;
for(int j=a[i];j<=a[n];j++)
{
f[j]+=f[j-a[i]];
}
}
printf("%d\n",cnt);
}
}