0
点赞
收藏
分享

微信扫一扫

ZCMU - 1111: 松哥的困惑II


题目链接:​​点击打开链接​​

题目大意:略。

解题思路:多重背包。

AC 代码

#include<bits/stdc++.h>

#define mem(a,b) memset(a,b,sizeof a)

using namespace std;

typedef long long ll;

const int MAXN = 10005;

int dp[MAXN];
int val[MAXN],weight[MAXN],num[MAXN];
int n,m,init;

void ZeroOne_Pack(int val,int weight,int m)
{
// for(int j=m;j>=weight;j--)
// dp[j]=max(dp[j],dp[j-weight]+val);

// 特殊情况,需要还原到原先最初 01背包 写法 j==[m,0]
for(int j=m-1;j>=0;j--) // 这里 j 从 m-1 开始是因为 j 如果从 m 开始(也可以)但结果不变,没意义
{
if(j+weight>m)
dp[m]=min(dp[m],dp[j]+val); // 类似 j+weight-weight
else
dp[j+weight]=min(dp[j+weight],dp[j]+val);
}
}

void Complete_Pack(int val,int weight,int m)
{
// for(int j=weight;j<=m;j++)
// dp[j]=max(dp[j],dp[j-weight]+val);

// 类似 01背包 一样修改,只需修改 完全背包 j 的特性即可
for(int j=0;j<=m-1;j++)
{
if(j+weight>m)
dp[m]=min(dp[m],dp[j]+val);
else
dp[j+weight]=min(dp[j+weight],dp[j]+val);
}
}

int Multi_Pack(int val[],int weight[],int n,int m)
{
for(int i=0;i<MAXN;i++) dp[i]=init;
dp[0]=0; // 避免 max/min 函数使用时,一直是init数据

for(int i=0;i<n;i++)
{
if(num[i]*weight[i]>m)
{
Complete_Pack(val[i],weight[i],m);
}
else
{
int k=1;
while(k<num[i])
{
ZeroOne_Pack(k*val[i],k*weight[i],m);
num[i]-=k;
k<<=1;
}
ZeroOne_Pack(num[i]*val[i],num[i]*weight[i],m);
}
}
return dp[m];
}

int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<n;i++)
scanf("%d",&weight[i]);
for(int i=0;i<n;i++)
scanf("%d",&val[i]);
int msum=0;
init=0;
for(int i=0;i<n;i++)
{
scanf("%d",&num[i]);
msum+=num[i]*weight[i];
init+=num[i]*val[i]; // 为初始化 dp[] 做准备,当然自定义一个数据也可,但可能发生意外,算出上界保险
}

Multi_Pack(val,weight,n,m);
printf(msum<m?"Impossible\n":"%d\n",dp[m]);
}

return 0;
}


举报

相关推荐

0 条评论