个人奇葩脑回路,没有看过分组背包,并非正解,但是可以AC
正解为分组背包
c[i][0]表示商家i需要的物品个数(个人习惯),c[i][j]表示商家i需要物品的价值
每次卖出物品都是当前商家需要的价值最高的物品,所以卖给相应商家的物品可以说是排序之后的,并且价值最高的物品需要减去邮费,因此需要前缀和
dp[i][j]表示前i个商家需要j个物品
状态转移方程:前 i-1 个商家的 j 个物品与第 i 个商家的前 z 个物品之和为dp[i-1][j]+w[i][z] ;
dp[i][j+z]=max(dp[i][j+z],dp[i-1][j]+w[i][z])
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int a[N];//邮费
struct no
{
int x;//价格
int y;//商家
}b[N];
bool cmp(int x,int y)
{
return x>y;
}
int c[N][N];//所有商家的全部价格
int w[N][N];//二维数组c的前缀和
int dp[N][N];//DP
int main()
{
int i,j,n,m,k,z;
cin>>n>>m>>k;
for(i=1;i<=m;i++)
cin>>a[i];
for(i=1;i<=n;i++)
cin>>b[i].x>>b[i].y;
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
if(b[j].y!=i) continue;
c[i][0]++;//【i】【0】表示商家i需要多少物品
c[i][c[i][0]]=b[j].x;//将价格存入相应商家序号的后面
}
}
for(i=1;i<=m;i++)
{
sort(c[i]+1,c[i]+c[i][0]+1,cmp);//排序
if(c[i][0]!=0) c[i][1]-=a[i];//价格最高的物品需要减去邮费
}
for(i=1;i<=m;i++)
{
for(j=1;j<=c[i][0];j++)
w[i][j]=w[i][j-1]+c[i][j];//前缀和
}
for(i=0;i<=1000;i++)
{
for(j=1;j<=1000;j++)
dp[i][j]=-1e8;//清空数组,这样才可以出现买东西赔钱的情况,比如物品50,邮费100的情况
}
for(i=1;i<=m;i++)//遍历商家
{
for(j=0;dp[i-1][j]!=-1e8&&j<=k;j++)//遍历上一个商家的所有情况
{
for(z=0;z<=c[i][0]&&j+z<=k;z++)//遍历当前商家的所有物品情况
{
if(i==1) dp[i][j+z]=w[i][z];
else dp[i][j+z]=max(dp[i][j+z],dp[i-1][j]+w[i][z]);//前面i-1个商家j个物品和第i个商家前z个物品
}
}
}
cout<<dp[m][k]<<endl;
return 0;
}