zoukankan      html  css  js  c++  java
  • 动态规划5--滑雪

    动态规划5--滑雪

    一、心得

    找路径时,递推的方法和递归一样,也是知道递推表达式之后就特别好写了
    也是直接把递推表达式写进循环里面就好了
    递推和递推写法的区别:
    递归是调用的系统栈,递推没有调用栈,其它一模一样了

    二、题目和分析

    滑雪:
    Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激。
    可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,
    你不得不再次走上坡或者等待升降机来载你。
    Michael想知道载一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子 1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9 一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。输入输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。输出输出最长区域的长度。
    输入
    输入的第一行表示区域的行数R和列数C
    (1 <= R,C <= 100)。下面是R行,每行有C个整数,
    代表高度h,0<=h<=10000。
    输出
    输出最长区域的长度。
    样例输入
    5 5
    1 2 3 4 5
    16 17 18 19 6
    15 24 25 20 7
    14 23 22 21 8
    13 12 11 10 9
    样例输出
    25

    先定义结构体把每个点的x,y和h都装起来,依次储存每个点。
    那这个问题就从二维化成了一维。
    按每个点高度从大到小排好。
    其实就变成了不下降子序列那个问题。
    具体做法:
    我按高度依次往后面找,看看后面的点是否满足点在这个点旁边的规则。
    满足的话就路径长度加1。

    L(i,j)表示从点(i,j)出发的最长滑行长度。
    一个点(i,j), 如果周围没有比它低的点,L(i,j) = 1
    否则
    递推公式: L(i,j) 等于(i,j)周围四个点中,比(i,j)低,且L值最大的那个点的L值,再加1
    复杂度:O(n2)

    解法1) “人人为我”式递推
    L(i,j)表示从点(i,j)出发的最长滑行长度。
    一个点(i,j), 如果周围没有比它低的点,L(i,j) = 1
    将所有点按高度从小到大排序。每个点的 L 值都初始化为1
    从小到大遍历所有的点。经过一个点(i,j)时,用递推公式求L(i,j)

    解法2) “我为人人”式递推
    L(i,j)表示从点(i,j)出发的最长滑行长度。
    一个点(i,j), 如果周围没有比它低的点,L(i,j) = 1
    将所有点按高度从小到大排序。每个点的 L 值都初始化为1
    从小到大遍历所有的点。经过一个点(i,j)时,要更新他周围的,比它高的点的L值。例如:
    if H(i+1,j) > H(i,j) // H代表高度
    L(i+1,j) = max(L(i+1,j),L(i,j)+1)

    三、代码和结果

      1 /*
      2 心得:
      3 找路径时,递推的方法和递归一样,也是知道递推表达式之后就特别好写了
      4 也是直接把递推表达式写进循环里面就好了
      5 递推和递推写法的区别:
      6 递归是调用的系统栈,递推没有调用栈,其它一模一样了  
      7 
      8 将题目转化为了求不下降子序列的长度 
      9 */ 
     10 #include <iostream>
     11 #include <algorithm>
     12 #define Max 105
     13 using namespace std;
     14 
     15 struct node{//表示每一个点 
     16     int r;//每一个点的行位置 
     17     int c;//每一个点的列位置 
     18     int h;//每一个点的高 
     19 };
     20 //排序规则,将结构从大到小排序 
     21 int my_comp(const node &p1,const node &p2){
     22     return p1.h>p2.h;
     23     //本来顺序是p1,p2,如果p1的高大于p2的高,我们就不交换 
     24 }
     25 node a[Max*Max];//储存每一个节点,按高度排序后将二维数组化成了一维数组 
     26 //dp[i]表示第i个点对应的最长区域的长度 
     27 int R,C,dp[Max*Max];//R表示行,R表示列 
     28 int pre[Max*Max];//记录每个点的路径 
     29 int maxn=0,maxn_i=R*C;//记录最长路径对应的点的值和编号 
     30 
     31 void input();//输入数据 
     32 void test_input(int R,int C);//测试输入数据 
     33 void init_dp();//动态规划前的初始化,初始化dp数组 
     34 void dpFunction();//dp操作 
     35 bool isClose(node a,node b);//判断两个点是否相连 
     36 void printRoad1(int i);//递归方法打印路径 
     37 void printRoad2(int i);//递推方法打印路径 
     38 
     39 
     40 
     41 
     42 int main(){
     43     freopen("in.txt","r",stdin);
     44     
     45     input();//输入数据 
     46     
     47     sort(a+1,a+R*C+1,my_comp);//对每个点按高度进行排序 
     48     //test_input(R,C); //测试输入数据 
     49     init_dp();//动态规划前的初始化,初始化dp数组
     50     dpFunction();//dp操作 
     51     //递归找路径 
     52     printRoad1(pre[maxn_i]);
     53     cout<<a[maxn_i].r<<","<<a[maxn_i].c<<endl;//输出第一个点 
     54     
     55     //递推找路径 
     56     //cout<<a[maxn_i].r<<","<<a[maxn_i].c;//输出第一个点
     57     //printRoad2(pre[maxn_i]);//输出后面的点 
     58     return 0;
     59 } 
     60 
     61 //递推方法打印路径 
     62 void printRoad2(int i){
     63     /*
     64     递推表达式是: 
     65     如果pre[i]==0,表示是起始点,return
     66     如果不是0,递归呗 
     67     */ 
     68     /*
     69     找路径时,递推的方法和递归一样,也是知道递推表达式之后就特别好写了
     70     也是直接把递推表达式写进循环里面就好了
     71     递推和递推写法的区别:
     72     递归是调用的系统栈,递推没有调用栈,其它一模一样了 
     73     */ 
     74     while(true){
     75         if(i==0){
     76             break;
     77         }
     78         else{
     79             cout<<"-->"<<a[i].r<<","<<a[i].c;
     80             i=pre[i];
     81         }
     82     }
     83 }
     84 
     85 //递归方法打印路径 
     86 void printRoad1(int i){
     87     /*
     88     递推表达式是: 
     89     如果pre[i]==0,表示是起始点,return
     90     如果不是0,递归呗 
     91     */ 
     92     if(i==0){
     93         return ;
     94     }    
     95     else{
     96         printRoad1(pre[i]);
     97         cout<<a[i].r<<","<<a[i].c<<"-->";    
     98     }
     99 }
    100 
    101 //dp操作
    102 void dpFunction(){
    103     //从高往低走,如果靠近,上下左右相邻四个点之一,最长区域就加1 
    104     for(int i=1;i<=R*C;i++){
    105         for(int j=1;j<i;j++){
    106             if(isClose(a[i],a[j])){
    107                 if(dp[j]+1>=dp[i]){
    108                     dp[i]=dp[j]+1;
    109                     pre[i]=j;
    110                 }
    111             }
    112         }
    113     }
    114     //路径最长的点并不是一定从最后面出来的那个点,所以cout<<dp[R*C]<<endl;是不对的 
    115     //还要找到dp里面那个最大的值,和那个值对应的编号 
    116     
    117     for(int i=1;i<=R*C;i++){ 
    118         if(dp[i]>maxn){
    119             maxn=dp[i];
    120             maxn_i=i;
    121         }
    122     }
    123     //cout<<maxn<<" "<<maxn_i<<endl;
    124     cout<<maxn<<endl;
    125     
    126 }
    127 
    128 //判断两个点是否相连 
    129 bool isClose(node a,node b){
    130     /*
    131             r-1
    132      c-1    r,c        c+1
    133             r+1
    134     */ 
    135     //对应上下左右,
    136     //r在前列子在后
    137     int direction[4][2]={{1,0},{-1,0},{0,-1},{0,1}}; 
    138 //    cout<<direction[0][0]<<endl;
    139 //    cout<<direction[0][1]<<endl;
    140 //    cout<<direction[1][0]<<endl;
    141 //    cout<<direction[1][1]<<endl;
    142     
    143     for(int i=0;i<4;i++){
    144         //a在中心 
    145         if((a.r+direction[i][0]==b.r)&&(a.c+direction[i][1]==b.c)){
    146             return true;
    147         }
    148     }
    149     return false;
    150     
    151 }
    152 
    153 //动态规划前的初始化,初始化dp数组 
    154 void init_dp(){
    155     for(int i=1;i<=R*C;i++){
    156         dp[i]=1;
    157     }
    158 }
    159 
    160 //输入数据 
    161 void input(){
    162     cin>>R>>C;
    163     int num=1;
    164     for(int i=1;i<=R;i++){
    165         for(int j=1;j<=C;j++){
    166             a[num].r=i;
    167             a[num].c=j; 
    168             cin>>a[num++].h;
    169         }
    170     } 
    171 }
    172 
    173 //测试输入数据 
    174 void test_input(int R,int C){
    175     for(int i=1;i<=R*C;i++){
    176         cout<<a[i].r<<" "<<a[i].c<<" "<<a[i].h<<endl;
    177     }
    178 }

  • 相关阅读:
    Redis宣言
    软件工程
    分布式编程
    编程泛型
    tcp/ip高效编程总结
    IP协议详解
    gevent程序员指南
    网站架构
    这些话,是乔布斯给世间留下的真正伟大礼物
    Flink/Spark 如何实现动态更新作业配置
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/6970882.html
Copyright © 2011-2022 走看看