例 Help Jimmy
题目链接:点击打开链接
解题思路
if(板子k左端正下方没有别的板子) {if(板子k的高度h(k)大于Max) LeftMinTime(k)=无穷大; else LeftMinTime(k)=h(k); } else if(板子k左端正下方的板子编号是m) LeftMinTime(k)=h(k)-h(m)+Min(LeftMinTime(m)+Lx(k)-Lx(m),RightMinTime(m)+Rx(m)-Lx(k)); }
代码实现:
/* POJ1661 Help Himmy 这样效率太低了,一早上没看几个题 代码要是不是特别好看懂,先把伪代码写出来就比较好懂了 分析: 将板子由高到低按从0到n编号,起始点的为0 不妨认为Jimmy开始的位置是一个编号为0,长度为0的板子 设LeftMinTime(k)表示从k号板子左端到地面的最短时间 RightMinTime(k)表示从k号板子右端到地面的最短时间 if ( 板子k左端正下方没有别的板子) { if( 板子k的高度 h(k) 大于Max) LeftMinTime(k) = ∞; else LeftMinTime(k) = h(k); } else if( 板子k左端正下方的板子编号是m ) LeftMinTime(k) = h(k)-h(m) + Min( LeftMinTime(m) + Lx(k)-Lx(m), RightMinTime(m) + Rx(m)-Lx(k)); } */ #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; #define MAX_N 1000 #define INFINITE 1000000 int t, n, x, y, maxHeight; struct Platform{//定义平台结构体 int Lx, Rx, h;//Lx表示做边界横坐标,Rx表示右边界横坐标,h表示高度 bool operator < (const Platform & p2) const {//符号重载,sort的时候能按h从高到低排 return h > p2.h; } }; Platform platForms[MAX_N + 10];//平台 int leftMinTime[MAX_N + 10];//走左边的最小时间 int rightMinTime[MAX_N + 10];//走右边的最小时间 int L[MAX_N + 10];// //l表示现在这块板的编号,越在上面的编号越小,bleft表示是否向左边走 //因为这题分为向左和向右两种情况 int MinTime(int l, bool bLeft)//l表示现在这块板的编号,越在上面的编号越小,bleft表示是否向左边走 { //初始化x和y坐标,如果是去左边,就走到左边边上,如果去右边,就走到右边边上 int y = platForms[l].h; int x; //如果是去左边,就走到左边边上,如果去右边,就走到右边边上 if (bLeft) x = platForms[l].Lx; else x = platForms[l].Rx; int i; for (i = l + 1; i <= n; i++) {//找到现在这块板下面的那块板 if (platForms[i].Lx <= x && platForms[i].Rx >= x)//判断从当前条能跳到的小一块板子上 break; } if (i <= n) {// 板子k左端正下方有别的板 if (y - platForms[i].h > maxHeight)// 跳到这块平台的高度如果大于Max return INFINITE;//返回无限大 } else {// 板子k左端正下方没有别的板 if (y > maxHeight)//板子k的高度 h(k) 大于Max return INFINITE;//返回无限大 else return y;//如果可以直接跳下,就输出y } int nLeftTime = y - platForms[i].h + x - platForms[i].Lx;//现在平台与下一块平台的高度差以及下一块平台左边界的距离 int nRightTime = y - platForms[i].h + platForms[i].Rx - x;//现在平台与下一块平台的高度差以及下一块平台右边界的距离 if (leftMinTime[i] == -1) //等于-1表示我初始化过 ,如果还可以向左我们就向左 leftMinTime[i] = MinTime(i, true);//向左进入子问题 if (L[i] == -1)//等于-1表示我初始化过 ,如果还可以向右我们就向右 L[i] = MinTime(i, false);//像右进入子问题 nLeftTime += leftMinTime[i];//左边固定花费的时间加上下一场左边这样的时间 nRightTime += L[i];//右边固定花费的时间加上下一场右边这样的时间 //返回左边和右边走中值小的那一个 if (nLeftTime < nRightTime) return nLeftTime; return nRightTime; } int main() { int t; cin>>t;//读入t组数据 for (int i = 0; i < t; i++) {//对每组数据进行操作 memset(leftMinTime, -1, sizeof(leftMinTime));//初始化leftMinTime memset(L, -1, sizeof(rightMinTime));//初始化L cin>>n>>x>>y>>maxHeight;//读入数据 platForms[0].Lx = x; platForms[0].Rx = x; platForms[0].h = y;//起始点初始化 for (int j = 1; j <= n; j++)//读入平台信息 cin>>platForms[j].Lx>>platForms[j].Rx>>platForms[j].h; sort(platForms, platForms + n + 1);//对平台由高到低排序 cout<< MinTime(0, true);//MinTime()方法求下平台的最小时间 } return 0; }
例 滑雪
代码实现:
扫描二维码关注公众号,回复:
1574829 查看本文章
#include<iostream> using namespace std; const int Max = 105; int row, col; int map[Max][Max]; // 记录图各点的高度。 int dp[Max][Max]; // 记录以各点为起点的最长下降路径的长度。 int dfs(int r, int c) { if (dp[r][c] != 0) return dp[r][c]; // 若dp[r][c]不为0,则表示它已被访问。 int max = 1; if (r + 1 <= row && map[r][c] > map[r + 1][c]) { int len = dfs(r + 1, c) + 1; if (len > max) max = len; } if (r - 1 >= 1 && map[r][c] > map[r - 1][c]) { int len = dfs(r - 1, c) + 1; if (len > max) max = len; } if (c + 1 <= col && map[r][c] > map[r][c + 1]) { int len = dfs(r, c + 1) + 1; if (len > max) max = len; } if (c - 1 >= 1 && map[r][c] > map[r][c - 1]) { int len = dfs(r, c - 1) + 1; if (len > max) max = len; } return map[r][c] = max; } int main() { int i, j; cin >> row >> col; for (i = 1; i <= row; i++) for (j = 1; j <= col; j++) cin >> map[i][j]; int ans = 0; memset(dp, 0, sizeof(dp));//给dp[][]全部初始化为0 for (i = 1; i <= row; i++) for (j = 1; j <= col; j++) { dp[i][j] = dfs(i, j); // 用记忆化搜索求出dp[i][j],同时也求出了其路径上的dp[x][y]。 if (dp[i][j] > ans) ans = dp[i][j]; } cout << ans << endl; return 0; }参考资料: 动态规划3--Help Jimmy