• ZOJ 3211 Dream City(DP)


    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3374

    题目大意:JAVAMAN 到梦幻城市旅游见到了黄金树,黄金树上每天回结出金子。已经有n棵树,JAVAMAN要停留m天,每天只能砍掉一棵树,砍掉树后就能得到树上的黄金。给定n棵树上原有的黄金a[i]和每天可以新增加的黄金b[i],求他最多可以得到多少黄金。中途如果有1天不砍树的话,之后的日子久不能砍树,所有最好每天都砍树,或者直到树被砍完。

    Sample Input

    2
    2 1
    10 10
    1 1
    2 2
    8 10
    2 3

    Sample Output

    10
    21

    Hints:
    Test case 1: JAVAMAN just cut tree 1 to get 10 gold coins at the first day.
    Test case 2: JAVAMAN cut tree 1 at the first day and tree 2 at the second day to get 8 + 10 + 3 = 21 gold coins in all.

    分析:凭借经验每天结果子越多的树越在最后砍,能得到最大收益。所以开始按照b[i]由小到大排序。

      令dp[i][j]表示在前 i 棵树中 j 天的最大收益,则答案为dp[n][m],很像背包。

    代码如下:

     1 # include<iostream>
     2 # include<cstdio>
     3 # include<cstring>
     4 # include<algorithm>
     5 using namespace std;
     6 
     7 int n,m;
     8 struct node
     9 {
    10     int a,b;
    11 } s[255];
    12 int dp[255][255];
    13 bool cmp(const node a,const node b)
    14 {
    15     return a.b < b.b;
    16 }
    17 
    18 int main()
    19 {
    20     int T,i;
    21     scanf("%d",&T);
    22     while(T--)
    23     {
    24         scanf("%d%d",&n,&m);
    25         for(i=1; i<=n; i++)
    26             scanf("%d",&s[i].a);
    27         for(i=1; i<=n; i++)
    28             scanf("%d",&s[i].b);
    29         sort(s+1,s+1+n,cmp);
    30         memset(dp,0,sizeof(dp));
    31         for(int i =1; i<=n; i++)
    32         {
    33             for(int j=1; j<=m; j++)
    34             {
    35                 dp[i][j] = max(dp[i-1][j],dp[i-1][j-1]+s[i].a+(j-1)*s[i].b);
    36             }
    37         }
    38         printf("%d
    ",dp[n][m]);
    39     }
    40     return 0;
    41 }

     这道题目最开始脑子里想的是记忆化搜索,却写成了DFS,结果当然超时。

     1 # include<iostream>
     2 # include<cstdio>
     3 # include<cstring>
     4 using namespace std;
     5 
     6 int n,m,maxx;
     7 int a[255],b[255],vis[255];
     8 
     9 void DP(int x,int y)
    10 {
    11     if(x > maxx)
    12         maxx = x;
    13     if(y > m)
    14         return ;
    15     int i;
    16     for(i=1; i<=n; i++)
    17     {
    18         if(vis[i]) continue;;
    19         vis[i] = 1;
    20         DP(x+a[i]+(y-1)*b[i],y+1);
    21         vis[i] = 0;
    22     }
    23 }
    24 int main()
    25 {
    26     int T,i;
    27     scanf("%d",&T);
    28     while(T--)
    29     {
    30         scanf("%d%d",&n,&m);
    31         for(i=1; i<=n; i++)
    32             scanf("%d",&a[i]);
    33         for(i=1; i<=n; i++)
    34             scanf("%d",&b[i]);
    35         maxx = 0;
    36         DP(0,1);
    37         printf("%d
    ",maxx);
    38     }
    39     return 0;
    40 }
    View Code

    这里为什么混淆呢?总结以下几点

    1.DFS和记忆化搜索都用到了新开的数组vis[]表示是否遍历过

    2.DFS中会vis[i]=1表示走过,之后还会vis[i]=0还原回来,但是记忆化搜索没有这个回溯的过程

    3.一般情况下,如果求n所对应的结果,DFS是从1开始,而记忆化搜索从结果开始,因为它只遍历一次

  • 相关阅读:
    MyBatis学习(三)
    MyBatis学习(二)
    Linux(Ubuntu)下MySQL的安装与配置
    IO 流读取文件时候出现乱码 文件编码格式问题 怎么转换解决方法
    spring boot下MultipartHttpServletRequest如何提高上传文件大小的默认值
    Mybatis 批量插入时得到插入的id(mysql)
    对PDF的操作
    利用nginx进行集群部署
    Spring boot学习笔记之@SpringBootApplication注解
    git的使用命令
  • 原文地址:https://www.cnblogs.com/acm-bingzi/p/3330815.html
Copyright © 2020-2023  润新知