【ZCMU2165】黄金矿工(分组背包)

题目链接

解题思路:

首先因为在同一直线上的黄金必须按顺序挖,所以可以将同一直线上的黄金所需时间和价值做前缀和处理,比如例1中,挖2 2的黄金之前必须先挖1 1,所以可以将2 2处黄金所需时间变为1+2,价值变为1+3,也就是说同一直线上的黄金都是同一组的,但是他们不可能同时存在,所以问题就转换为了分组背包问题。

代码:

#include<bits/stdc++.h>
using namespace std;
int dp[40005],N;
map<double,int>m;
struct kuang{
	int x,y;
	int t;
	int v;
}a[205],b[205][205];
bool cmp(kuang a,kuang b)
{
	double x=a.x/a.y;
	double y=b.x/b.y;
	if(x==y)return a.x<b.x;
	else return x<y;
}
int main()
{
	int T,i,ans=0;
	scanf("%d%d",&N,&T);
	memset(dp,0,sizeof(dp));
	for(i=0;i<N;i++){
		scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].t,&a[i].v);
		double x=(double)a[i].x/(double)a[i].y;
		if(!m.count(x))m[x]=1;
		else m[x]++;		
	}
	sort(a,a+N,cmp);
	int t,k,num[205],j=0;
	for(i=0;i<N;i=i+t){
		double x=(double)a[i].x/(double)a[i].y;
		int z=0;
		t=m[x];
		//printf("t=%d\n",t);
		b[j][z]=a[i];
		for(k=i+1;k<i+t;k++){
			z++;
			b[j][z]=a[k];
			b[j][z].v=b[j][z-1].v+a[k].v;
			b[j][z].t=b[j][z-1].t+a[k].t;
		}
		z++;
		num[j]=z;
		j++;
	}
	for(i=0;i<m.size();i++){
		for(j=T;j>=0;j--){
			for(k=0;k<=num[i];k++){
				if(j>=b[i][k].t)dp[j]=max(dp[j-b[i][k].t]+b[i][k].v,dp[j]);
				ans=max(ans,dp[j]);
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39826163/article/details/81320026