ZOJ 3211 Dream City
贪心,$dp$。
假设我们知道要选择哪些物品,那么这些物品应该按什么顺序选择呢?
物品$A(a1,b1)$,物品$B(a2,b3)$。
假设物品$A$在第$x$天被选择,物品$B$在第$y$天被选择。$x<y$。那么收益为:$P1=a1+(x-1)*b1+a2+(y-1)*b2$。
假设物品$A$在第$y$天被选择,物品$B$在第$x$天被选择。$x<y$。那么收益为:$P2=a1+(y-1)*b1+a2+(x-1)*b2$。
$P1>P2$的条件为:$(x-1)*b1+(y-1)*b2>(y-1)*b1+(x-1)*b2$,即$(y-x)*(b2-b1)>0$,即$b2>b1$。
也就是说,假设我们知道要选择哪些物品,那么这些物品按$b$从小到大取获得的收益最大。
因此,我们可以降物品按照$b$从小到大排序,然后去决策应该选择哪些物品,$dp$即可。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<ctime> #include<iostream> using namespace std; typedef long long LL; const double pi=acos(-1.0); void File() { freopen("D:\\in.txt","r",stdin); freopen("D:\\out.txt","w",stdout); } template <class T> inline void read(T &x) { char c = getchar(); x = 0; while(!isdigit(c)) c = getchar(); while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); } } int T,n,m; struct X { int a,b; }s[300]; bool cmp(X a, X b) { return a.b<b.b; } int dp[300][300]; int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&s[i].a); for(int i=1;i<=n;i++) scanf("%d",&s[i].b); sort(s+1,s+1+n,cmp); memset(dp,0,sizeof dp); dp[1][1]=s[1].a; for(int i=2;i<=n;i++) dp[i][1]=max(dp[i-1][1],s[i].a); for(int j=2;j<=m;j++) { for(int i=j;i<=n;i++) { dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]+s[i].a+(j-1)*s[i].b); } } printf("%d\n",dp[n][m]); } return 0; }