1. 程式人生 > >【JZOJ100044】abcd【DP】【揹包】

【JZOJ100044】abcd【DP】【揹包】

題目大意:

題目連結:https://jzoj.net/senior/#main/show/100044
題目圖片:
http://wx4.sinaimg.cn/mw690/0060lm7Tly1fy7h522lqej30j50dk3zl.jpg
http://wx4.sinaimg.cn/mw690/0060lm7Tly1fy7h522g0rj30jv0h3glu.jpg
http://wx1.sinaimg.cn/mw690/0060lm7Tly1fy7h5226qpj30j204vgli.jpg
給定 a ,

b , c , d a,b,c,d 四個陣列,求 e e
,使得
{ a i e
i b i i = 1 n e i × c i = 0 m a x { i = 1 n e i × d i } \left\{\begin{matrix}a_i\leq e_i\leq b_i\\ \sum^{n}_{i=1}e_i\times c_i=0\\ max\{\sum^{n}_{i=1}e_i\times d_i\}\end{matrix}\right.

m a x { i = 1 n e i × d i } max\{\sum^{n}_{i=1}e_i\times d_i\}


思路:

看得出是一個多重揹包嗎?
對於第 i i 個“物品”:

  • 價值 d i d_i
  • 重量 c i c_i
  • a i a_i\leq 個數 b i \leq b_i

首先,由於必須選擇至少 a i a_i 個物品 i i ,所以就直接取走 a i a_i 個物品 i i 。剩餘 b i a i b_i-a_i 個物品 i i
那麼就是一個模板的多重揹包了。
用二進位制拆分變成 01 01 揹包,然後求出 f [ m ] f[m] ,最終答案就是 f [ m ] + f[m]+ 必須選的部分。


程式碼:

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

const int N=200010;
int n,m,s,a,b,c,d,ans,sum,w[N],v[N],f[N];

int main()
{
	scanf("%d",&s);
	while (s--)
	{
		scanf("%d%d%d%d",&a,&b,&c,&d);
		sum+=a*d;  //必須選
		m-=a*c;
		b-=a;
		for (int i=1;i<=b;i*=2)  //二進位制拆分
		{
			w[++n]=i*c;
			v[n]=i*d;
			b-=i;
		}
		if(b) w[++n]=b*c,v[n]=b*d;
	}
	memset(f,0x80,sizeof(f));
	f[0]=0;
	for (int i=1;i<=n;i++)  //揹包
		for (int j=m;j>=w[i];j--)
			f[j]=max(f[j],f[j-w[i]]+v[i]);
	printf("%d\n",f[m]+sum);
	return 0;
}