题意:(至少选一个)
有n种品牌的鞋子,m元钱,k种鞋子
每种鞋子有三种属性:品牌,价值,价格
每种品牌至少买一双,问用m元最多买多少价值的鞋子?
解析:
这题和普通的分组背包不同,这里每种至少一个,可以多选
定义状态dp[i][v]表示买了i种物品,用来v钱,收获的最大价值
每个牌子至少买一双,这个可以用初始化dp[i][j]=-inf,dp[0]=0,来处理
dp[1][j]一定是从dp[0]转化来打,以此类推,知道dp[k]
转移方程:
dp[i][v]=max(dp[i][v],dp[i][v-vc[i][j].p]+vc[i][j].v);//注意顺序
dp[i][v]=max(dp[i][v],dp[i-1][v-vc[i][j].p]+vc[i][j].v);
这里要注意这两个方程的顺序,因为vc[i][j].p可能==0,所以如果顺序反了,一件物品可能买了两次
ac:
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
#define MAXN 10005
using namespace std;
struct node
{
int v,p;
};
vector<node> vc[11];
ll dp[11][MAXN];
int main()
{
int n,m,k,a,b,c;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
for(int i=0;i<=k;i++)
vc[i].clear();
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&a,&b,&c);
vc[a].push_back({c,b});
}
memset(dp,-inf,sizeof(dp));
memset(dp[0],0,sizeof(dp[0]));
for(int i=1;i<=k;i++)
{
int len=vc[i].size();
for(int j=0;j<len;j++)
{
for(int v=m;v>=vc[i][j].p;v--)
{
dp[i][v]=max(dp[i][v],dp[i][v-vc[i][j].p]+vc[i][j].v);//注意顺序
dp[i][v]=max(dp[i][v],dp[i-1][v-vc[i][j].p]+vc[i][j].v);
}
}
}
if(dp[k][m]<0)
printf("Impossible\n");
else
printf("%lld\n",dp[k][m]);
}
return 0;
}
题意:(至多选一个)
给一个矩阵a[][]
a[i][j]表示用j天学习第i个课程能够得到A[i][j]的收益
求m天内获得的收益最大值,一天只能上一节课
ac:
#include<bits/stdc++.h>
#define MAXN 105
using namespace std;
int dp[MAXN],a[MAXN][MAXN];
int main()//分组背包
{
int n,m,i,j,k;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
break;
memset(dp,0,sizeof(dp));
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
scanf("%d",&a[i][j]);
}
}
for(i=0;i<n;i++)//这三个循环的顺序决定了不会取同一组的物品
{
for(j=m;j>=0;j--)
{
for(k=0;k<j;k++)
{
dp[j]=max(dp[j],dp[j-k-1]+a[i][k]);
}
}
}
printf("%d\n",dp[m]);
}
return 0;
}