滑雪问题的几个解法

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更长。事实上,这是最长的一条。

Input
输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。

Output
输出最长区域的长度。


      最初看到这个问题,是在(
http://www.cppblog.com/qywyh/archive/2006/03/01/3616.aspx) ,下面是该blog 作者的一个解法:  这个解法中的回溯很经典,在回溯中运用动态规划,代码如下:

#include <iostream>
using namespace std;

const int MAX = 102;
const int HIGHT = 10001;
struct pos {
    int i, j , p ;
};
int path(int [MAX][MAX], int [MAX][MAX] , int [MAX][MAX], int , int) ;

int main(int argc,char * argv[])
{
    int input[MAX][MAX];
    int result[MAX][MAX];
    int status[MAX][MAX];
    int m,n;

    int i,j;
    int max, ans;
    cin >> m >> n;
    for(i = 0 ; i <= m + 1; i ++)
        for(j = 0 ; j <= n + 1; j ++)
        {
            input[i][j] = HIGHT ;
            result[i][j] = 0;
            status[i][j] = 0;
        }
    for(i = 1; i <= m ; i++)
        for(j = 1; j <= n ; j++)
            cin >> input[i][j];
    clock_t  t1 = clock();
    for(i = 1; i <= m ; i++)
        for(j = 1; j <= n ;j ++)
            path(input,result,status,i,j);
    max = 0;
    for(i = 1; i <= m ; i++)
        for(j = 1; j <= n ; j ++)
            if( max < result[i][j])
                max = result[i][j];
    clock_t t2 = clock();
    cout <<"Time is : " << t2 - t1 <<endl;
    cout << max <<endl;
    return 0;
}

int path(int input[MAX][MAX], int result[MAX][MAX], int status[MAX][MAX],int i , int j)
{
    pos pack[MAX * MAX];
    int max,g,h;
    int ii;
    int top = 0;
    int p = 0;
    int incr[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};
    if(result[i] [ j] > 0 ) return 0;
    else {
        pack[top].i = i;
        pack[top].j = j;
        pack[top].p = p;
        status[i][j] = - 1;
    }
    while(top >= 0 || p < 4) {
        if(p < 4) {
            g = pack[top].i + incr[p][0];
            h = pack[top].j + incr[p][1] ;

            if(input[pack[top].i][pack[top].j] > input[g][h] )
            {
                if(result[g][h] > 0 || status[g][h] == -1)
                    p ++;
                else {
                    top ++ ;
                    pack[top].i = g;
                    pack[top].j = h;
                    pack[top].p = p;
                    status[g][h] = -1;
                    p = 0 ;
                }
            }
            else p++;
        } else {
            max = 0;
            for(ii = 0 ; ii < 4; ii ++) {
                g = pack[top].i + incr[ii][0];
                h = pack[top].j + incr[ii][1];
                if(input[pack[top].i][pack[top].j] > input[g][h] && max < result[g][h])
                    max = result[g][h];
            }
            result[pack[top].i][pack[top].j] = max + 1;
            top --;
            p = pack[top].p + 1;
        }
    }
    return 0;
}

   


     这个问题,可以完全用递归来解决,感这个问题完全用递归来解决好像比上面两种解法快一些:

#include  < iostream >

using   namespace  std;
int  hight[ 100 ][ 100 ]
;
int  R,C ;
bool inline left_lower( int  row, int  col)
{
    
if (col  >=   1 ) {
        
if (hight[row][col  -   1 <  hight[row][col])  return   true ;
        
return   false ;
    }
    
return   false ;
}
bool inline right_lower( int  row, int  col)
{
    
if (col  +   1   >=  C)  return   false ;
    
if (hight[row][col + 1 <  hight[row][col])  return   true ;
        
return   false ;    
}
bool inline up_lower( int  row, int  col)
{
    
if (row  >=   1 ) {
        
if (hight[row - 1 ][col]  <  hight[row][col])  return   true ;
        
return   false ;
    }
    
return   false ;
}
bool  down_lower( int  row,  int  col)
{
    
if (row  +   1   >=  R)  return   false ;
    
if (hight[row + 1 ][col]  <  hight[row][col])  return   true ;
    
return   false ;
}
int  step( int  row,  int  col)
{
    
if (row  <   0   ||  col  <   0  )  return   0 ;
    
if (row  >=  R  ||  col  >=  C)  return   0 ;
    
int  m  =   0  ;
    
int  tmp   =   - 1 ;
    
if (left_lower(row,col)  ==   true ) {
        tmp 
=  step(row ,col  -   1 );
    }
    
if ( tmp  >  m ) m  =  tmp;
    
if (right_lower(row,col)  ==   true ) {
        tmp 
=  step(row,col + 1 );
    }
    
if (tmp  >  m ) m  =  tmp;
    
if (up_lower(row,col)  ==   true ) {
        tmp 
=  step(row - 1 ,col);
    }
    
if (tmp > m) m  =  tmp ;
    
if (down_lower(row,col)  ==   true ) {
        tmp 
=  step(row + 1 ,col);
    }
    
if (tmp  >  m) m  =  tmp;
    
return  m  +   1 ;
}
int  main()
{
    
int  i,j;
    
int  max  =   0  ;
    
int  tmp;
    cin 
>> >>  C ;
    
for (i  =   0  ; i  <  R ; i  ++ )
        
for (j  =   0  ; j  <  C ; j ++ )
            cin 
>>  hight[i][j];
    clock_t t1 
=  clock();
    
for ( i  =   0  ; i  <  R; i  ++ )
        
for  (j  =   0  ; j  <  C ; j  ++ )
        {
            
// printf("[%d,%d] =%d ", i+1,j+1,step(i,j));
            tmp  =  step(i,j);
            
if (tmp  >  max) {
                max 
=  tmp;
            }
        }
    clock_t t2 
=  clock();
    cout 
<<   " Time is :  "   <<  t2  - t1  << endl;
    
out << " The max is :   " << max <<endl;
   
return   0 ;                
}

      附上生成测试数据的小程序:
#include  < iostream >
#include 
< cstdio >
#include 
< ctime >

using   namespace  std;
int  main( int  argc, char   *  argv[])
{
    
int  i ,j , tmp ;
    
int  m,n;
    
if (argc  !=   3 ) {
        cerr 
<<   " please input row-col "   << endl;
        exit(
0 );
    }
    
// cin >> m >>n;
    m  =  atoi(argv[ 1 ]);
    n 
=  atoi(argv[ 2 ]);
    cout 
<<  m  <<   '   ' <<  n  <<  endl;
    srand(time(NULL));
    
for  ( i  =   0  ; i  <  m; i ++ ) {
        
for (j  =   0 ; j  <  n; j  ++ )
        {
            tmp 
=   0  ;
            
while (tmp  ==   0 ) {
             tmp 
=  rand()  %   10000 ;
             srand(time(NULL) 
+  tmp);
            }
            cout 
<<  tmp  <<   '   ' ;
        }
        cout 
<< endl;
    }
    
return   0 ;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值