题目: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;
}