zoukankan      html  css  js  c++  java
  • 【上海交大oj】纸来纸去(动态规划)

    Description

    晔神和纯哥是好基友,他们一刻不交谈就甚是想念对方。一节课上,班上同学被强制安排坐成一个m行n列的矩阵,而晔神被安排在左上角,坐标(1,1);纯哥被安排在右下角,坐标(m,n),因此,他们就无法直接交谈了。幸运的是,班上的热心同学们可以通过传纸条来帮助他们进行交流,但从晔神传到纯哥的纸条只可以向下或者向右传递,从纯哥传给晔神的纸条只可以向上或者向左传递,并且每位同学只能帮助他们传递一次。

    除了每人只能帮忙一次之外,同学们的热心度也有不同,这关系到晔神和纯哥交谈的成功率!晔神和纯哥希望同学们帮他们一来一回传递两次纸条(即两条路径),并使得传递过程中同学们的热心程度之和最大。现在,请你帮助晔神和纯哥找到符合他们急迫心情的两条路径。

    Input Format

    输入的第一行有2个用空格隔开的整数m和n,表示同学们的座位有m行n列。

    接下来的m行,每行有n个自然数,记作aij,表示第i行j列的学生的热心程度。每行数之间用空格隔开。(1<=aij<=100)

    Output Format

    输出为一个整数,表示一来一回过程中同学们的热心度之和的最大值。

    Limits

    30%的数据满足:1<=m,n<=10

    100%的数据满足:1<=m,n<=50

    Sample Input

    3 3
    0 3 9
    2 8 5
    5 7 0
    

    Sample Output

    34
    

    Hint

    两条路径同时进行

    考虑到纸条所在位置的坐标与时间的关系,通过这个关系可以把4维数组压缩到3维


    二维的动态规划题,和三线捡苹果类似,我是采用一行一行动归的,这样只需记录上一行的状态就行了,可以节省空间,但比较麻烦,容易出错。对于每一行,两条线路的位置一定是可以上一行的位置直接向下一步达到的,当然也可能是右移所达到的,但是每个点只能走一次,也就是说右边的线路始终在左边的右方,为了避免出现线路重叠的情况,可以这么做:一个两重循环遍历这一行的左右两点位置,对于每一个垂直达到的状态位置:(左:j右:k)左线路能平移范围为j-k-1,右线路平移范围为k-n-1,写一个两重循环来更新通过平移达到的状态。
    代码:
     1 #include <iostream>
     2 #include <cstring>
     3 using namespace std;
     4 
     5 int m,n;
     6 int map[55][55];
     7 int last[55][55]; //上一行 
     8 int now[55][55]; //当前行 
     9 int main(){
    10     cin>>m>>n;
    11 
    12     for (int i = 0;i < m;++i)
    13         for (int j = 0;j < n;++j) cin>>map[i][j];
    14     memset(last,0,sizeof(last));
    15     last[0][0] = map[0][0];
    16     for (int i = 1;i < n;++i) last[0][i] = last[0][i-1] + map[0][i];
    17     for (int i = 1;i < m;++i){
    18         memset(now,0,sizeof(now));
    19         for (int j = 0;j < n-1;++j){   //
    20             for (int k = j+1;k < n;++k){ //遍历不平移的两点位置 
    21                 int tmp = last[j][k];
    22                 for (int l = j;l < k;++l){ //遍历平移情况下的状态 
    23                     tmp += map[i][l];
    24                     int t = tmp;
    25                     for (int p = k;p < n;++p){
    26                         t += map[i][p];
    27                         if (t > now[l][p]) now[l][p] = t;
    28                     }
    29                 }
    30             
    31             }
    32         }
    33         for (int j = 0;j < n;++j)     //更新一行 
    34             for (int k = 0;k < n;++k) last[j][k] = now[j][k];
    35 
    36     }
    37     cout<<now[n-2][n-1]<<endl;
    38     
    39     return 0;
    40 }
    View Code
  • 相关阅读:
    iMX287A嵌入式Qt环境搭建
    iMX287A多种方法实现流水灯效果
    iMX287A交叉编译环境搭建
    cmake用法及常用命令总结(全)
    webrtc中AGC的应用
    h264和aac封装flv
    C/C++读写文件的几种方法fstream fopen、fwrite()、fread()操作
    关于Git无法提交 index.lock的解决办法
    git回滚到任意版本
    Git Submodule管理项目子模块
  • 原文地址:https://www.cnblogs.com/wenma/p/4668519.html
Copyright © 2011-2022 走看看