P1757 分组背包

题目描述:

题目传送门


解题思路:

依题意得,同组内的元素会互相冲突,也就是说同一组只能选一个,也就是说在组内做01背包。

我们先来看看伪代码:

for 所有的组k
    for v=V..0
        for 所有的i属于组k
      f[v]=max{
    
    f[v],f[v-w[i]]+c[i]}

第一重循环比较好理解,就是一组一组下去的做01背包。但是for v=V..0必须放在for 所有的i属于组k的外面,这是为了保证在当前容量中,每一个同组的物品只会选到一个。
如:
当枚举到 f v f_v fv 时, f v = m a x ( f v   ,   f v − w i + v i ) f_v=max(f_v\ ,\ f_{v-w_i}+v_i) fv=max(fv , fvwi+vi),显然, f v − w i f_{v-w_i} fvwi 是选到上一组的时候的最优解,不包括选取当前组内物品的情况,不会影响每一组只选一个的特性。


CODE:

#include <iostream>
#include <cstring>
using namespace std;
int V,n,t;
struct Gar
{
    
    
	int v[5000],w[5000],len;
} a[200];
long long f[100100]={
    
    0};
int main()
{
    
    
	cin>>V>>n;
	for(int i=1;i<=n;i++)
	  {
    
    
	  	int b,c,d;
	  	cin>>b>>c>>d;
	  	t=max(t,d);  //最大的组数就是组的总数
	  	a[d].w[a[d].len+1]=b;  //将物品分组方便选择
	  	a[d].v[a[d].len+1]=c;
	  	a[d].len++;
	  }
	for(int i=1;i<=t;i++)
	  {
    
    
	  	for(int j=V;j>=0;j--)
	  	  {
    
    
	  	    for(int k=1;k<=a[i].len;k++)
			  {
    
    
			  	if(j<a[i].w[k]) continue;  //如果当前容量不能放下当前物品,则跳过
			  	f[j]=max(f[j],f[j-a[i].w[k]]+a[i].v[k]);
			  }	
		  }
	  }
	cout<<f[V];
	return 0;
} 

再给一道练习巩固:
TENSHI在经历了无数次学科竞赛的失败以后,得到了一个真理:做一题就要对一题!但是要完全正确地做对一题是要花很多时间(包括调试时间),而竞赛的时间有限。所以开始做题之前最好先认真审题,估计一下每一题如果要完全正确地做出来所需要的时间,然后选择一些有把握的题目先做。 当然,如果做完了预先选择的题目之后还有时间,但是这些时间又不足以完全解决一道题目,应该把其他的题目用贪心之类的算法随便做做,争取“骗”一点分数。
任 务根据每一题解题时间的估计值,确定一种做题方案(即哪些题目认真做,哪些题目“骗”分,哪些不做),使能在限定的时间内获得最高的得分,

Input

第一行有两个正整数N和T,表示题目的总数以及竞赛的时限(单位秒)。以下的N行,每行4个正整数W1i 、T1i 、W2i 、T2i ,分别表示第i题:完全正确做出来的得分,完全正确做出来所花费的时间(单位秒),“骗”来的分数,“骗”分所花费的时间(单位秒)。
其中,3 ≤ N ≤ 30,2 ≤ T ≤ 1080000,1 ≤ W1i 、W2i ≤ 30000,1 ≤ T1i 、T2i ≤ T。

Output

所能得到的最高分值

Sample Input

样例1
4 10800
18 3600 3 1800
22 4000 12 3000
28 6000 0 3000
32 8000 24 6000

样例2
3 7200
50 5400 10 900
50 7200 10 900
50 5400 10 900
Sample Output

样例1
50

样例2
70
Source

elba

猜你喜欢

转载自blog.csdn.net/SAI_2021/article/details/121572016