hdu 5501 The Highest Mark

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5501

贪心+动态规划,贪心确定做题顺序,动态规划选定做哪些题目。

对于任意一个做题序列x1,x2,。。。,xm,对于该序列中任意的相邻两项xi,xi+1,交换这相邻的两项,只会对这两道题的得分有影响,对其余的题目不会产生影响。

设在时刻t,分值为X,开始做题xi,xi+1,则分值变为X1=X+[Ai-Bi*(Ci+t)]+[Ai+1-Bi+1*(Ci+Ci+1+t)];若做题xi+1,xi,则分值为X2=X+[Ai+1-Bi+1*(Ci+1+t)]+[Ai-Bi*(Ci+Ci+1+t)],若X1<X2,则需要交换这两项,即BiCi+1 >Bi+1Ci,等价于Bi/Ci > Bi+1/Ci+1。所以对于一个确定的题目集合,做题的最优顺序只与每道题目的Bi/Ci有关,按每道题目的B/C排序,按照比值由大到小做题。

然后就是按照排好的顺序,选择做哪些题目,即0/1背包,状态转移方程也同0/1背包。

#include<cstdio>
#include<cstdlib>
#include<vector>
#include<cstring>
#include<set>
#include<queue>
#include<stack>
#include<map>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<bitset>
using namespace std;
#define N 10005
#define NMAX 2000000000 
typedef long long ll;

struct type{
	int a;
	int b;
	int c;
	double f;
}p[N];
int dp[N*3];
bool cmp(const type& x, const type& y){
	return x.f > y.f;
}
int main(){
	int T, n, m, t;
	while ( scanf("%d", &T) != EOF){
		while ( T > 0 ){
			T--;
			scanf("%d %d", &n, &t);
			for ( int i = 0; i < n; i++ ){
				scanf("%d %d %d", &p[i].a, &p[i].b, &p[i].c);
				p[i].f = (double)p[i].b / p[i].c;
			}
			sort(p, p+n, cmp);
			memset(dp, -1, sizeof(dp));
			dp[0] = 0;
			for ( int i = 0; i < n; i++ ){
				for ( int j = t; j >= p[i].c; j-- ){
					if ( dp[j-p[i].c] == -1)continue;
					if ( dp[j-p[i].c]+p[i].a-(j*p[i].b) > dp[j] )
						dp[j] = dp[j-p[i].c]+p[i].a-(j*p[i].b);
				}
			}
			m = 0;
			for ( int i = 0; i <= t; i++ ){
				if ( dp[i] > m ) m = dp[i];
			}
			cout << m << endl;
		}
	} 
	return 0;
} 
 


你可能感兴趣的:(hdu 5501 The Highest Mark)