(来源于mooc郭炜老师的 程序设计与算法(二):算法基础 课程)(我只是个思路的搬运工,代码是我自己写的以供参考,不过本人不才这个代码提交到poj上超时了,我不知道怎么优化,所以这篇文章即是分享也是请教,希望大牛可以教教我怎么优化这个代码)
解题思路:
Jimmy跳到一块板子上可以向左走也可以向右走,走到左边或者右边这个时间我们是很容易计算的。
如果我们知道以左端为起点到达地面的最短时间,和以右端为起点到达地面的最短时间,那么我们就可以在向左走还是向右走两个选项中选择那个花费时间更少的。
这样我们就可以将整个问题分解为两个子问题:1.Jimmy所在位置下方第一块板子左端为起点到地面的最短时间 2.以右端为起点到地面的最短时间
这两个子问题在形式上和原问题一致。和子问题相关的变量就只有板子编号。
(懒得打字了,直接上图)
下面是我自己写的代码(超时了):
#include <iostream>
#include <cmath>
using namespace std;
int N;
int Max;
struct banzi {//板子的信息
int height;
int left;
int right;
} ban[1000];
int leftmintime(int k);
int rightmintime(int k);
void quicksort(struct banzi ban[], int Left, int Right);//将板子从高到低排序编号
int getlow(int k, bool L);//得到编号k板子下一块板子编号
int main() {
int t;
cin >> t;
int x, y;
while (t--) {
scanf("%d%d%d%d", &N, &x, &y, &Max);
ban[0].left = ban[0].right = x;
ban[0].height = y;
for (int i = 1; i <= N; i++)
cin >> ban[i].left >> ban[i].right >> ban[i].height;
quicksort(ban, 1, N);
cout << leftmintime(0) << endl;
}
}
int leftmintime(int k) {
int m;
m = getlow(k, true);
if (m == N + 1) {
if (ban[k].height <= Max)
return ban[k].height;
else
return 999999;
} else {
return ban[k].height - ban[m].height +
min(leftmintime(m) + ban[k].left - ban[m].left, rightmintime(m) + ban[m].right - ban[k].left);
}
}
int rightmintime(int k) {
int n;
n = getlow(k, false);
if (n == N + 1) {
if (ban[k].height <= Max)
return ban[k].height;
else
return 999999;
} else {
return ban[k].height - ban[n].height +
min(leftmintime(n) + ban[k].right - ban[n].left, rightmintime(n) + ban[n].right - ban[k].right);
}
}
void quicksort(struct banzi ban[], int Left, int Right) {
if (Left >= Right)
return;
int i = Left, j = Right;
int key = ban[Left].height;
while (i < j) {
while (ban[j].height <= key && i < j)
j--;
while (ban[i].height >= key && i < j)
i++;
if (i < j) {
struct banzi t = ban[i];
ban[i] = ban[j];
ban[j] = t;
}
}
struct banzi temp = ban[Left];
ban[Left] = ban[i];
ban[i] = temp;
quicksort(ban, Left, i - 1);
quicksort(ban, i + 1, Right);
}
int getlow(int k, bool L) {
int i;
if (L) {
for (i = k + 1; i <= N; i++) {
if (ban[i].left < ban[k].left && ban[i].right > ban[k].left)
break;
}
} else {
for (i = k + 1; i <= N; i++) {
if (ban[i].left < ban[k].right && ban[i].right > ban[k].right)
break;
}
}
return i;
}