DP动态规划--基础题-滑雪(POJ-1088)

DP–基础题-滑雪

原题点这里

题目:

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

Sample Input
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

Sample Output
25

题目解析:

  • 本题题意很简单,一个二维数组存放该点的高度,每个点都可以向四邻的点进行“滑行”,算最长的滑行距离
  • 此题可以用搜索做,我们这里还是讲动态规划(DP)的做法:
    首先如果从某点开始的一个序列是最长的一个递降序列,那么它的后缀头开始的最长序列则应该是该点的后缀序列。
A
B
C
D
K
E
F
G

同理反推,如图,若C的最长递降序列为C-D-K,F的最长递归序列为F-G,则E的最长递降序列是只能从F后缀和C后缀里挑,经过对比可以得到E的最长递归序列为E-C-D-K。
这样通过自低到高的反推dp则可以得到所有点的最长递降序列长度。

由于要对点的高低进行排序,我使用了结构数组和stl的自定义sort

不多说,上代码

参考AC代码:

#include<iostream>
#include<algorithm>
using namespace std;
typedef struct grid {
	int x, y;
	int h;
	grid() {};
	grid(int x0, int y0, int h0) : x(x0), y(y0), h(h0) { };
};
bool cmp(grid a, grid b) {
	return a.h < b.h;
}
int dx[5] = { 1,0,-1,0 };
int dy[5] = { 0,-1,0,1 };
int main()
{
	int R, C;
	grid g[10010];
	int h[101][101];//存放该点的高度
	int dp[101][101];//存放该点开始的最长滑雪距离
	int k = 0;
	cin >> R >> C;
	for (int i = 0; i < R; i++) {
		for (int j = 0; j < C; j++) {
			cin >> h[i][j];
			dp[i][j] = 1;//dp初始化为1,表示所有点的初始最长滑雪距离为1
			g[k++] = grid(i, j, h[i][j]);
		}
	}
	sort(g, g + C * R, cmp);
	for (int i = 0; i < C * R; i++) {
		//int nowh = g[i].h;
		for (int d = 0; d < 4; d++) {//遍历四邻点
			int xi = g[i].x + dx[d];
			int yi = g[i].y + dy[d];
			if (xi >= 0 && xi < R && yi>=0 && yi < C) {
				if (h[xi][yi]<g[i].h && dp[xi][yi] + 1>dp[g[i].x][g[i].y]) {//如果该邻点为低点则进行dp
					dp[g[i].x][g[i].y] = dp[xi][yi] + 1;//更新dp数组
				}
			}
		}
	}
	int MAX = -1;
	for (int i = 0; i < R; i++) {
		for (int j = 0; j < C; j++) {
			MAX = max(dp[i][j], MAX);//找到最大滑雪距离值
		}
	}
	cout << MAX << endl;
	return 0;
}

总结:
本题应该很轻松就能看出其dp的属性并得出递推关系。稍加打磨并利用好结构数组便能很轻松地解出来,我第一次比赛里做居然没能AC

有兴趣的同学dp做完后可以试试搜索的做法,后续学习过程中或许我也会给出搜索的解法。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
POJ - 3616是一个目,目描述如下: 给定一组区间,每个区间有一个权重,要求选择一些区间,使得这些区间的右端点都小于等于k,并且权重之和最大。请问最大的权重和是多少? 解决这个问的思路是使用动态规划。首先,将区间按照左端点从小到大进行排序。然后,定义一个dp数组,dp[i]表示右端点小于等于i的所有区间所能得到的最大权重。 接下来,遍历每一个区间,对于每个区间i,将dp[i]初始化为区间i的权重。然后,再遍历i之前的每个区间j,如果区间j的右端点小于等于k,并且区间j的权重加上区间i的权重大于dp[i],则更新dp[i]为dp[j]加上区间i的权重。 最后,遍历整个dp数组,找到最大的权重和,即为所求的答案。 下面是具体的代码实现: ```cpp #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct interval{ int start, end, weight; }; interval intervals[10005]; int dp[10005]; int n, m, k; bool compare(interval a, interval b) { if (a.start == b.start) { return a.end < b.end; } else { return a.start < b.start; } } int main() { while(~scanf("%d %d %d", &n, &m, &k)) { memset(dp, 0, sizeof dp); for (int i = 0; i < m; i++) { scanf("%d %d %d", &intervals[i].start, &intervals[i].end, &intervals[i].weight); } sort(intervals, intervals + m, compare); for (int i = 0; i < m; i++) { dp[i] = intervals[i].weight; for (int j = 0; j < i; j++) { if (intervals[j].end <= k && dp[j] + intervals[i].weight > dp[i]) { dp[i] = dp[j] + intervals[i].weight; } } } int maxWeight = 0; for (int i = 0; i < m; i++) { maxWeight = max(maxWeight, dp[i]); } printf("%d\n", maxWeight); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值