滑雪

滑雪

问题描述

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。
输出
输出最长区域的长度。

输入样例
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

定义状态co[i][j]为到坐标为(i,j)的点的最长路径
可以用动态规划的思路解决。在读入时按照点的高度排序,在接下来从低到高(从高到底亦可),有以下关系:
对于一个点而言,其路径长度无非是从四周比其低的点转移来的,不然则说明自己即为周遭最低的点。因此co[i][j] = max(co[i - 1][j], co[i + 1][j], co[i][j - 1], co[i][j + 1], 1)

另一种解法将这个问题视为“最长路”问题, 人为设定一个虚拟节点, 距离为0, 能走到任何节点,接下来即可用单源点最长路解决问题。
虚拟终点的设定也适用于最短路问题。

以下为动态规划代码。

//ski
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

struct point{
    int r;
    int c;
    point(int _r, int _c){
        r = _r;
        c = _c;
    }
};


//var & const
const int maxN = 101;
int r, c;
int height[maxN][maxN];
int co[maxN][maxN];
vector<point> p[10010];
int maks = 0;
int finalM = 0;

//func
void init();
void readin();
int findSmallest();
void print();
void calcCount();

bool checkbound(int _c, int _r);
bool islower(int c, int r, int c1, int r1);

int main(){
    init();
    readin();
    calcCount();
    print();
    return 0;
}

void init(){
    freopen("ski.in", "r", stdin);
    freopen("ski.out", "w", stdout);
    r = c = 0;
    memset(height, -1, sizeof(height));
    memset(co, -1, sizeof(co));
}

void readin(){
    cin >> r >> c;
    for (int i = 1; i <= r; i++){
        for (int j = 1; j <= c; j++){
            cin >> height[i][j];
            p[height[i][j]].push_back(point(i, j));
            if (height[i][j] > maks) maks = height[i][j];
        }
    }
}

int findSmallest(){
    for (int i = 0; i <= maks; i++){
        if (!p[i].empty()){
            return i;
        }
    }
    return -1;
}

bool checkbound(int _c, int _r){
    return (0 <= _c && _c <= c) && (0 <= _r && _r <= r);
}

bool islower(int c, int r, int c1, int r1){
    return (height[r][c] < height[r1][c1]);
}

void calcCount(){
    int s = findSmallest();
    for (int i = 0; i < p[s].size(); i++){
        co[p[s][i].r][p[s][i].c] = 1;
    }
    for (int i = s; i <= maks; i++){
        for (int j = 0;j < p[i].size(); j++){
            int c = p[i][j].c;
            int r = p[i][j].r;
            co[r][c] = 1;
            if (checkbound(c - 1, r) && islower(c - 1, r, c, r)) co[r][c] = max(co[r][c], co[r][c - 1] + 1);
            if (checkbound(c + 1, r) && islower(c + 1, r, c, r)) co[r][c] = max(co[r][c], co[r][c + 1] + 1);
            if (checkbound(c, r + 1) && islower(c, r + 1, c, r)) co[r][c] = max(co[r][c], co[r + 1][c] + 1);
            if (checkbound(c, r - 1) && islower(c, r - 1, c, r)) co[r][c] = max(co[r][c], co[r - 1][c] + 1);
            if (co[r][c] > finalM) finalM = co[r][c];
        }
    }
}

void print(){
    cout << finalM << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值