Zoj 3211 Dream City (DP)

题目链接: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原创,但可以转载,因为我们是兄弟。

你可能感兴趣的:(Zoj 3211 Dream City (DP))