一、Description

原题链接

和poj1088同样的题目

【题目描述】

benben喜欢滑雪。(以下简叙)在一个(R*C(R,Cleq100))的整数矩阵上找一条高度严格递减的最长路。起点任意,但每次只能沿着上下左右4个方向之一走一格,并且不能走出矩阵外。如图所示,最长路是按照高度25,24,23,…,2,1 这样走,长度为25。矩阵中的数均为0~100.

【输入格式】

有多组数据。

第一行为一个整数N,表示数据组数。 对于每组数据,第一行包括一个字符串和两个整数R,C,为此滑雪者的姓名和矩阵的长宽。

【输出格式】

对于每组数据,输出一行,格式为: name: answer

name为当前数据的滑雪者姓名,answer为你的答案。

【输入输出样例】

输入:

2
Feldberg 10 5
56 14 51 58 88
26 94 24 39 41
24 16 8 51 51
76 72 77 43 10
38 50 59 84 81
5 23 37 71 77
96 10 93 53 82
94 15 96 69 9
74 0 62 38 96
37 54 55 82 38
Spiral 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

输出:

Feldberg: 7
Spiral: 25

二、Soulution

这是一道动态规划的题目,(dp[i][j])表示到达((i,j))点的时候最长路的值,初始化都为1

首先按照整数矩阵的值的大小对每个点从大到小排序,然后更新每个点的(dp[][])值,也就是状态转移;

((i,j))点的整数值小于周围的点并且,(dp[i][j])小于周围某个点的(dp+1)的时候,表示周围的某个点可以下滑到((i,j)),那么更新(dp[i][j])为周围那个点的(dp+1)

这里为什么要先从大到小排序呢?可以将整个整数矩阵理解成一座座山相连,局部最大的值就是一个山的山峰。我们想得到其中一个山的高度(由该山峰出发的最大下滑距离),由于一开始dp值都是1,必须先得到较高的点的dp值,才能根据它更新较低点的dp值。

《算法基础与在线实践》书上动态规划这一节有讲这个poj1088的题目,递推也有两种思路。

一种是“人人为我”,就是由上下左右的点更新当前的点的dp值(也就是我下面代码采用的)

另一种就是“我为人人”,就是由当前的点,更新上下左右的点的dp值

当然两者更新的时候都要先判度四周的点是否符合条件:一是没有越界;二是要从高的点滑向低的点;

#include<iostream>
#include<string> 
#include<vector>
#include<algorithm>
using namespace std;
struct Node{
	int value;
	int i;
	int j;
};

bool cmp(const Node a, const Node b) //结构体的比较函数 
{
	return a.value > b.value; 
}
int main()
{
	int t;
	cin >> t;
	string name;
	int row, col;
	while(t--) {
		cin >> name >> row >> col;
		
		vector<vector<int>> map(row, vector<int>(col, 0));
		vector<vector<int>> dp(row, vector<int>(col, 1));  // dp[i][j]表示到(i,j)点的时候最大的下滑距离 
														   // 初始都是1!!! 
		struct Node nodes[row*col];
		
		int k = 0;
		for(int i = 0; i < row; ++i) {
			for(int j = 0; j < col; ++j) {
				cin >> map[i][j];
			
				nodes[k].i = i;
				nodes[k].j = j;
				nodes[k].value = map[i][j];
				k++;
			}
		}
	    
	    sort(nodes, nodes + row*col, cmp);  // 按照value从大到小排序 
	    
	    dp[nodes[0].i][nodes[0].j] = 1;
	    int ans = 0;
	    for(int i = 1; i < row*col; ++i) {
	    	
	    	int x = nodes[i].i;
	    	int y = nodes[i].j;
	    	int value = nodes[i].value;
	    	
			// 由上、下、左、右的点更新该点的值 
			if (y-1 >= 0 && value < map[x][y-1]) {
				dp[x][y] = max(dp[x][y], dp[x][y-1] + 1);	
			}
			if (y+1 < col && value < map[x][y+1]) {
				dp[x][y] = max(dp[x][y], dp[x][y+1] + 1);	
			}
	    	if (x-1 >= 0 && value < map[x-1][y]) {
	    		dp[x][y] = max(dp[x][y], dp[x-1][y] + 1);
			}
			if (x+1 < row && value < map[x+1][y]) {
				dp[x][y] = max(dp[x][y], dp[x+1][y] + 1);	
			}		

			ans = max(ans, dp[x][y]);

		}
		
		cout << name << ":" << " " << ans << endl;
	}
	
	return 0;
	
 }