Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 13277 | Accepted: 4408 |
Description
![](https://i-blog.csdnimg.cn/blog_migrate/0b9f30603f1b35df0918f9dc606d9d8b.jpeg)
场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。
Jimmy老鼠在时刻0从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束。
设计一个程序,计算Jimmy到底地面时可能的最早时间。
Input
Jimmy的大小和平台的厚度均忽略不计。如果Jimmy恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保证问题一定有解。
Output
Sample Input
1 3 8 17 20 0 10 8 0 10 13 4 14 3
Sample Output
23
中文题意不解释。
这道题很明显要用dp了。
用dp[i][0]和dp[i][1]分别表示第i块木板从左端点出发到达地面的最短时间和第i块木板从右端点出发到达地面的最短时间。
具体的状态转移方程(以计算dp[i][0]为例)就是先找到左端正下方的木板,但这块木板并不一定是相邻的木板,而是要对之前的所有木板进行遍历,如果左端点处于当前正在遍历的木板的左右端点之间,则说明这块木板j就是左端点正下方的木板。
所以dp[i][0]就取第j块木板的左端点到达地面所花时间+到达左端点所花时间+两木板的高度差和右端点到达地面所花时间+到达右端点所花时间+两木板的高度差两者取小的那个。
坑点1:需要判断两者的高度差是否小于等于max_h
如果此端点正下方没有木板,那就判断当前木板距离地面的高度,如果小于max_h,dp[i][0]就等于这块木板的高度(直接跳至地面)否则就将这个值置为inf
右端点做相同的处理。
但这里其实还有一个trick。应该把最高点看作是一个长度为0,高度为Y,左端点=右端点=X的木板加入计算。
否则的话还需要多加一层判断。(因为最高点不一定跳到最高的一块木板上,甚至可以不跳到木板上直接跳至地面)
坑点2:边缘也算在木板上。
本来我处理的时候就是这么想的。
奈何、、、少打了一个等号orz wa了四五遍
果然写代码的时候还是要仔细啊。不要说像之前还把break漏掉等更多低级错误了。
下面上代码。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <string>
#include <iostream>
#include <math.h>
#include <queue>
#include <vector>
int n,t;
const int maxn = 3e4+10;
const int inf = 268430090;
using namespace std;
bool used[maxn];
char maze[50][50];
typedef pair<int,int> P;
int a[maxn];
int dp[maxn][2];
int dis[maxn];
typedef struct Node
{
int x1,x2;
int h;
} node;
int cmp(const void *a, const void *b)
{
node pa = *(node*)a,pb = *(node*)b;
return pa.h-pb.h;
}
int main()
{
// std::ios::sync_with_stdio(false);
int T;
scanf("%d",&T);
int N,X,Y,max_h;
while(T--)
{
node a[maxn];
scanf("%d%d%d%d",&N,&X,&Y,&max_h);
memset(dp,-1,sizeof(dp));//一开始全部初始化为-1
for(int i = 1; i <= N; i++)
scanf("%d%d%d",&a[i].x1,&a[i].x2,&a[i].h);
a[N+1].x1 = X;a[N+1].x2 = X;a[N+1].h = Y;//将出发点也加入进行计算
qsort(a+1,N,sizeof(node),cmp);//按高度进行排序
for(int i = 1; i <= N + 1; i++)
{
//计算左端点
for(int j = i-1; j >= 1; j--)
{
if(a[i].x1 >= a[j].x1 && a[i].x1 <= a[j].x2 && a[i].h-a[j].h <= max_h)//要判断两点距离是否能跳
{
dp[i][0] = min(a[i].x1 - a[j].x1 + dp[j][0],a[j].x2 - a[i].x1+dp[j][1]) + a[i].h - a[j].h;
break;
}
}
if(dp[i][0] == -1)//如果当前端点下方没有木板
{if(a[i].h <= max_h)dp[i][0] = a[i].h;
else dp[i][0] = inf;}//否则置为inf
for(int j = i-1; j >= 1; j--)
{
if(a[i].x2 >= a[j].x1 && a[i].x2 <= a[j].x2 && a[i].h-a[j].h <= max_h)
{
dp[i][1] = min(a[i].x2 - a[j].x1 + dp[j][0],a[j].x2 - a[i].x2+dp[j][1]) + a[i].h - a[j].h;
break;
}
}
if(dp[i][1] == -1)
{if(a[i].h <= max_h)dp[i][1] = a[i].h;
else dp[i][1] = inf;}
}
int ans = min(dp[N+1][0],dp[N+1][1]);
printf("%d\n",ans);
}
这道题好像还有建图然后用最短路做的。。
在练dp还是好好练吧。
唉 还是菜 这好像是简单dp题吧