hdu1171 Big Event in HDU(多重背包)

思路来源

https://www.cnblogs.com/liuzhanshan/p/6024567.html

题意

有n种仪器,每种仪器i对应一个v[i]即价值,m[i]即数量,

hdu计院和软院要分开了,将这些仪器的价值尽可能的均分,

如果不能均分,计院所得多一点,问各分多少价值。

题解

以价值的一半为背包容量,软院尽可能放满背包,剩下的给计院即可。

考虑到每种限制数量,即为多重背包。

以下为多重背包核心代码:

        rep(i,0,n-1)
   	{
   		rep(k,0,num[i]-1)
   		{
   			per(j,cap,v[i])
   			dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
   		}
   	}

cap为背包容量,这里为价值sum/2,

若不含k的循环,即为01背包;

加上k的循环,相当于,

k=2的时候,dp[j]可以从k=1的dp[j-v[i]]的最优情况转移而来,

dp[j-v[i]]在上一轮循环中已确定好选1件还是不选,

递推可知,

每一轮内层循环per的内部,相当于01背包,

外层的k循环每次相当于利用上一次k-1的最佳结果,最终选定k个,相当于限定个数。

心得

这题memory开得比较小,而似乎也只能这么O(n*maxM*\sum v[i]/2)做,勉强卡时间吧。

第一发TLE,第二发MLE,第三发这么写才过......

不过也学到了一个滚动数组的写法,也可以勉强过...

即只利用dp[i]和dp[i+1],dp[0]和dp[1]不断滚动;对2取余,保留最后两次结果即可。

代码1(多重背包)

#include <iostream>
#include <algorithm> 
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const int INF=0x3f3f3f3f;
const int maxn=1e5+10; 
const int mod=1e9;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int> 
#define si set<int>
#define pii pair<int,int> 
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a)) 
using namespace std;
int n,num[55],v[55],dp[250005],tot,cap;
void init()
{
	mem(num,0);
	mem(v,0);
	mem(dp,0);
	tot=0;
}
int main()
{ 
   while(~scanf("%d",&n)&&n>0)
   {
   	init();
   	rep(i,0,n-1)
   	{
   		sci(v[i]);
		sci(num[i]);
		tot+=v[i]*num[i];
   	}
   	cap=tot/2;//背包容量 
   	rep(i,0,n-1)
   	{
   		rep(k,0,num[i]-1)
   		{
   			per(j,cap,v[i])
   			dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
   		}
   	}
   	printf("%d %d\n",tot-dp[cap],dp[cap]);
   }
   return 0;
}

代码2(滚动数组)

#include <iostream>
#include <algorithm> 
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const int INF=0x3f3f3f3f;
const int maxn=1e5+10; 
const int mod=1e9;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int> 
#define si set<int>
#define pii pair<int,int> 
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a)) 
using namespace std;
int n,num[55],v[55],dp[2][250005],tot;
void init()
{
	mem(num,0);
	mem(v,0);
	mem(dp,0);
	tot=0;
}
int main()
{ 
   while(~scanf("%d",&n)&&n>0)
   {
   	init();
   	rep(i,0,n-1)
   	{
   		sci(v[i]);
		sci(num[i]);
		tot+=v[i]*num[i];
   	}
   	rep(i,0,n-1)
   	{
   		rep(j,0,tot/2)
   		{
   			for(int k=0;k<=num[i];++k)
   			{
   				if(j-k*v[i]<0)break;
				dp[(i+1)&1][j]=max(dp[(i+1)&1][j],dp[i&1][j-k*v[i]]+k*v[i]);
   			}
   		}
   	}
   	int q=tot/2;
   	printf("%d %d\n",tot-dp[n&1][q],dp[n&1][q]);
   }
   return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值