动态规划入门(二)DP 基本思想 具体实现 经典题目 POJ1088

来源:互联网 发布:图片相册制作软件 编辑:程序博客网 时间:2024/06/16 21:17

(一) POJ1088,动态规划的入门级题目。嘿嘿,连题目描述都是难得一见的中文。

题目分析

求最长的滑雪路径,关键是确定起点,即从哪开始滑。

不妨设以( i, j )为起点,现在求滑行的最长路径。

首先,( i, j )能滑向的无非就是它四周比它低的点。到底滑向哪个点?很简单,谁长滑行谁。假设(i, j )--->( i, j+1 ), 现在就变成了:以( i, j+1 )为起点,求最长滑行路径的问题。这样一直下去,直到某个局部最低点,就算滑行结束了。


状态转换方程

dp( i,j ) = Max( dp( i-1, j ), dp( i, j+1 ),dp( i+1, j ), dp( i, j-1 ) ) + 1;

其中:dp( i,j )表示以( i, j )为起点,所能滑行的最长长度 

编程实现

枚举起点,找到最长的滑行路径。因为涉及到上下左右的点,所以注意边界情况的处理。还是记忆化递归来的简便,直接把Invalid的情况给剪掉。

下面是代码:


/* * 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更长。事实上,这是最长的一条。 */import java.util.Scanner;public class DP{private int row;// 行数private int col;// 列数private int[][] height; // 存放各个点的高度private int maxLength = 0;private int[][] flag; // 存放从各个点开始的最长长度 ,主要实现动态规划,不再重复计算同样点的最大长度private int[] path = new int[1000];// 保存最长路径上的点public DP(int i, int j){// 构造函数this.row = i;this.col = j;height = new int[row][col];flag = new int[row][col];create();}// 给二维数组赋值public void create(){Scanner scan = new Scanner(System.in);for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){height[i][j] = (int) scan.nextInt();// 初始化各个点的高度值flag[i][j] = -1;// 初始化flag数组}}}public int max_Len(int i, int j){// 递归求最大值int max = 0;int[] temp ={ 1, 1, 1, 1 };// temp存放点height[i][j]的上下左右四个方向的最大长度if (flag[i][j] != -1){return flag[i][j];} else{if (j > 0 && height[i][j - 1] <= height[i][j])// 当可以向左滑动时{// 当可以向左滑动时 temp[0]=max[i][j-1]+1,否则temp[0]=0;下面类似temp[0] = max_Len(i, j - 1) + 1;}if (j < col - 1 && height[i][j + 1] <= height[i][j])// 向右{temp[1] = max_Len(i, j + 1) + 1;}if (i > 0 && height[i - 1][j] <= height[i][j]) // 向上{temp[2] = max_Len(i - 1, j) + 1;}if (i < row - 1 && height[i + 1][j] <= height[i][j])// 向下{temp[3] = max_Len(i + 1, j) + 1;}// for循环找出从height[i][j]出发的最大长度for (int k = 0; k < temp.length; k++){if (max < temp[k]){max = temp[k];}}flag[i][j] = max;return max;}}/** * 默认取temp[i]=1是因为当该点不能向继续滑动时,应返回1 */// 返回最大长度public void maxLength(){int x = 0;int y = 0;// x,y记录坐标位置for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){if (maxLength < max_Len(i, j)){maxLength = max_Len(i, j);x = i;y = j;}}}System.out.println("最大长度为:" + (maxLength));System.out.print("最大路径:");printPath(x, y);}public void printPath(int a, int b){// 打印最长路径int i = a;int j = b;int x = 0;int y = 0;// x y记录.坐标int max = 0;while (maxLength > 0){int[][] temp = new int[row][col];// 暂存前后左右四个方向滑行的长度以及坐标System.out.print(height[i][j] + " ");// 输出最长路径上的点if (j > 0 && height[i][j - 1] < height[i][j]){// 向左试探temp[i][j - 1] = flag[i][j - 1];}if (j < col - 1 && height[i][j + 1] < height[i][j]){// 向右试探temp[i][j + 1] = flag[i][j + 1];}if (i > 0 && height[i - 1][j] < height[i][j]){// 向前试探temp[i - 1][j] = flag[i - 1][j];}if (i < row - 1 && height[i + 1][j] < height[i][j]){// 向后试探temp[i + 1][j] = flag[i + 1][j];}for (int m = 0; m < row; m++){// 求前后左右四个方向滑雪最大长度点for (int n = 0; n < col; n++){if (max < temp[m][n]){max = temp[m][n];x = m;y = n;}}}i = x;j = y;max = 0;// i j max重新赋值maxLength--;}}public static void main(String[] args){int i;int j;Scanner scanner = new Scanner(System.in);i = scanner.nextInt();// 行j = scanner.nextInt();// 列DP m = new DP(i, j);m.maxLength();}}


c++


#include <iostream>using namespace std;//***********************常量定义*****************************const int MAX = 105;//*********************自定义数据结构*************************//********************题目描述中的变量************************int row;int col;int data[MAX][MAX];//**********************算法中的变量**************************//dp[i][j]表示从data[i][j]出发所能滑行的最大长度int dp[MAX][MAX];//***********************算法实现*****************************int DP( int r, int c ){//如果已经计算过,则直接返回if( dp[r][c] > 0 ) return dp[r][c];int ans = 0;int tmp = 0;//只对有效的r、c进行计算if( r - 1 >= 1 ){//剪枝:只能滑行更低的点if( data[r][c] > data[r-1][c] ){tmp = DP( r-1, c );if( ans < tmp ) ans = tmp;}}if( r + 1 <= row ){if( data[r][c] > data[r+1][c] ){tmp = DP( r+1, c );if( ans < tmp ) ans = tmp;}}if( c - 1 >= 1 ){if( data[r][c] > data[r][c-1] ){tmp = DP( r, c-1 );if( ans < tmp ) ans = tmp;}}if( c + 1 <= col ){if( data[r][c] > data[r][c+1] ){tmp = DP( r, c+1 );if( ans < tmp ) ans = tmp;}}//如果是普通点,由状态转换方程//DP(i,j) = max( DP(i,j-1), DP(i,j+1), DP(i-1,j), DP(i+1,j) ) + 1;//如果是某个局部最低点,则返回 0 + 1 = 1dp[r][c] = ans + 1;return dp[r][c];}void Solve(){int ans = 0;for( int i=1; i<=row; i++ ){for( int j=1; j<=col; j++ ){int tmp = DP( i, j );if( ans < tmp ) ans = tmp;}}cout << ans << endl;cout<<"-----------------"<<endl;for( int i=1; i<=row; i++ ){for( int j=1; j<=col; j++ ){cout<< dp[i][j]<<" ";}cout<<endl;}}//************************main函数****************************int main(){//freopen( "in.txt", "r", stdin );cin >> row >> col;for( int i=1; i<=row; i++ ){for( int j=1; j<=col; j++ ){cin >> data[i][j];}}//输出for( int i=1; i<=row; i++ ){for( int j=1; j<=col; j++ ){cout<< data[i][j]<<" ";}cout<<endl;}Solve();system("pause");return 0;}



阅读全文
0 0
原创粉丝点击