题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3374
题目大意:给定n棵摇钱树,一开始每棵树上有ai的钱,每天以bi的速度涨钱,神树啊。主角每天砍一棵树,连续砍m天,不能间断。问最多可以能得多少钱?
解题思路:今天做了浙江2009年的省赛,一共出了7题,排名还算靠前,但是一点也不欣慰--这题简单的贪心+动规竟然没出。练了那么久DP,还被水题淹,真是蛋疼菊紧啊。
我想第一个原因是没有想到贪心的那个策略---斜率小的物品,如果在某个阶段不选,那么在以后都不会再选。因为它增长得慢,如果在开始的时候没选它,那到后面别人长得比它快就肯定轮不到它了。其次,是没把这个问题转化为背包,是的,它就是个背包,n个物品我们选m个物品,只是每个物品的价值是随天数增加的,但是贪心的性质保证了能够按照正常的背包去选择。
dp[i][j]表示i件物品选择j件的最大价值。状态转移方程:dp[i][j] = max(dp[i-1][j],dp[i-1][j-1]+val+(j-1)*xk) (val为初始值,xk为每天增加的价值)
测试数据:
2
2 1
10 10
1 1
2 2
8 10
2
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define max(a,b) (a)>(b)?(a):(b) struct node { int val,xk; }arr[310]; int n,m,dp[310][310]; int cmp(node a,node b) { return a.xk < b.xk; } int main() { int i,j,k,t,cur; scanf("%d",&t); while (t--) { scanf("%d%d",&n,&m); for (i = 1; i <= n; ++i) scanf("%d",&arr[i].val); for (i = 1; i <= n; ++i) scanf("%d",&arr[i].xk); sort(arr+1,arr+1+n,cmp); memset(dp,0,sizeof(dp)); for (i = 1; i <= n; ++i) for (j = 1; j <= m; ++j){ //既保证了连续,又保证了取m个,而且dp[i][j]最大 cur = dp[i-1][j-1]+arr[i].val+(j-1)*arr[i].xk; dp[i][j] = max(dp[i-1][j],cur); } printf("%d\n",dp[n][m]); } }
本文ZeroClock原创,但可以转载,因为我们是兄弟。