qduoj ycb的ACM进阶之路(貌似01的多重背包)

Description

  ycb是个天资聪颖的孩子,他的梦想是成为世界上最伟大的ACMer。为此,他想拜附近最有威望的dalao为师。dalao为了判断他的资质,给他出了一个难题。dalao把他带到一个到处都是题的oj里对他说:“孩子,这个oj里有一些不同的题,做每一道题都需要一些时间,每一题也有它自身的rp(人品值)。我会给你一段时间,在这段时间里,你可以做一些题。如果你是一个聪明的孩子,你应该可以让做题的总rp最大。”   如果你是ycb,你能完成这个任务吗?

Input

输入文件的第一行是一个T,表示测试组数,接下来T组每组第一行包含两个正整数N,M。M表示总共能够用来做题的时间,N代表oj里的题目的数目。接下来的N行每行包括两个的整数,分别表示做每个题的时间Ti和这道题的人品值Vi。 1 <= N, M <= 100000, 1 <= Ti, Vi <= 10

Output

输出文件仅包含一个整数表示规定时间内可以做题得到的最大人品值。

Sample Input 1 

1
3 9 
10 10 
8 1 
1 2

Sample Output 1

3

思路:Ti,Vi都非常小,所以我们可以开一个二维数组记录每一个[Ti,Vi],然后跑一个多重背包二进制优化即可.二进制优化就是每次选1,2,4,8...直到不能取为止,剩下的那些也算在里面,这样所有的可能取值都能用这些表示出来,然后对每种取法跑个01背包即可.

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 1000000007
using namespace std;
typedef long long ll;
const int maxn = 2e5+5;
const double esp = 1e-12;
const int ff = 0x3f3f3f3f;
map<int,int>::iterator it;

int n,m;
int mp[12][12];
int dp[maxn];

void init()
{
	mem(mp,0);
	mem(dp,0);
}

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		init();
		scanf("%d %d",&n,&m);
		
		for(int i = 1;i<= n;i++)
		{
			int a,b;
			scanf("%d %d",&a,&b);
			mp[a][b]++;
		}
		
		for(int i = 1;i<= 10;i++)
		{
			for(int j = 1;j<= 10;j++)
			{
				int sum = mp[i][j],k = 1;
				while(sum> k)
				{
					for(int l = m;l>= k*i;l--)
						dp[l] = max(dp[l],dp[l-k*i]+k*j);
					
					sum-= k;
					k*= 2;
				}
				
				if(!sum) continue;
				for(int l = m;l>= sum*i;l--)
					dp[l] = max(dp[l],dp[l-sum*i]+sum*j);
			}
		}
		
		printf("%d\n",dp[m]);
	}	
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/nka_kun/article/details/80229419