zoukankan      html  css  js  c++  java
  • SCNU 2015ACM新生赛决赛【F. Oyk闯机关】解题报告

     
          题目大意:一个$N imes N$的阵列,每个格子有$X_{ij}$个调和之音,若每次只能选择走右边或下边,从左上角出发走到右下角,问最多能收集到多少个调和之音?
     
          这题是一道很很很简单的DP题,但可能之前没接触过的同学需要一点脑能量去思考。。如果用最蠢的办法,循环枚举每种选择,求出最大值的话,由于你总共需要往右走$N-1$次,往下走$N-1$次,路径总长度为$2N-2$,根据组合数学,总共有$C_{2N-2}^{N-1}$种走法,想想$C_{1998}^{999}$会是一个多么可怕的数字,不用说这铁定是会超时的,而且铁定会超到地老天荒。怎么办呢?
     
          有的同学可能会考虑:能不能用贪心算法做呢?即每次只有两个选择,我每次都选择最大的那个,那么最终得到的结果是否在整体上是最大的呢?很遗憾这是错的,因为你每次只能往右或往下走,走当前的最大步无法证明走过最小步后,不会产生一条更大的路径。以上两种方案详细的分析参见51Nod - 动态规划入门篇 - 矩阵取数问题(注意先注册登录)。
     
          因此这题非DP不可了,考虑当前格子$X_{ij}$,它要么从$X_{i-1,j}$走过来,要么从$X_{i,j-1}$走过来,因此我只需要做两次循环,给每个格子判断一下从左边来的值更大,还是从上边来的值更大,然后跟这个格子的值相加,这样对于每个格子来说,它的值一定是从左上角到这个格子的最大值。在读入数据的时候就可以计算了。时间复杂度$O(N^2)$,空间复杂度$O(N^2)$。
     1 #include <stdio.h>
     2 
     3 inline int max(int&a, int&b) {
     4     return a>b?a:b;
     5 }
     6 
     7 int T, N, mat[1001][1001];
     8 int main() {
     9     scanf("%d", &T);
    10     while(T--) {
    11         scanf("%d", &N);
    12         for(int i=1; i<=N; i++)
    13             for(int j=1; j<=N; j++) {
    14                 scanf("%d", mat[i]+j);
    15                 mat[i][j]+=max(mat[i-1][j], mat[i][j-1]);
    16             }
    17         printf("%d
    ", mat[N][N]);
    18     }
    19     return 0;
    20 }
     
          然后我们再想想,空间复杂度$O(N^2)$其实是没必要哒!因为给每个格子判断只会用到它左边和上边的格子,也就是说只需要保存上一行就行了,判断完这一行的格子就可以覆盖掉了,上两行以上根本没必要保留,因为我们只要求最大值,不是求产生的最大值的路径,因此没必要保存下来(这是ACM中的滚动数组技术)。于是空间复杂度愉快地降到了$O(N)$。
     1 #include <stdio.h>
     2 
     3 inline int max(int&a, int&b) {
     4     return a>b?a:b;
     5 }
     6 
     7 int T, N, mat[1001], x;
     8 int main() {
     9     scanf("%d", &T);
    10     while(T--) {
    11         scanf("%d", &N);
    12         for(int i=1; i<=N; i++)
    13             mat[i]=0;
    14         for(int i=1; i<=N; i++)
    15             for(int j=1; j<=N; j++) {
    16                 scanf("%d", &x);
    17                 mat[j]=max(mat[j-1], mat[j])+x;
    18             }
    19         printf("%d
    ", mat[N]);
    20     }
    21     return 0;
    22 }
     
          比较遗憾的是,现场没有多少人能够做出来这道简单DP题,如果模仿去年新生赛决赛其中一题的难度,即求到终点对某个数$P$取模的最大值的话,估计会更惨。。。。

    ——by BlackStorm, from herehttp://www.cnblogs.com/BlackStorm/p/5043638.html .

  • 相关阅读:
    力扣 227 :基本计算器(II)
    力扣 224 :基本计算器(I)
    力扣 888:公平的糖果棒交换(哈希表法)
    力扣 1047 :删除字符串中的所有相邻重复项
    力扣 1423 :可获得的最大点数
    vue+spreadjs+后台Java实现与服务端交互的导入导出
    webpack 中 require.context() 多个模块的加载
    dwd_fact_coupon_use
    dwd_fact_cart_info
    dwd_fact_order_detail
  • 原文地址:https://www.cnblogs.com/BlackStorm/p/5043638.html
Copyright © 2011-2022 走看看