1 题目地址:猛戳我
2.
Help Jimmy
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 8223 | Accepted: 2629 |
Description
"Help Jimmy" 是在下图所示的场景上完成的游戏。
场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。
Jimmy老鼠在时刻0从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束。
设计一个程序,计算Jimmy到底地面时可能的最早时间。
场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。
Jimmy老鼠在时刻0从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束。
设计一个程序,计算Jimmy到底地面时可能的最早时间。
Input
第一行是测试数据的组数t(0 <= t <= 20)。每组测试数据的第一行是四个整数N,X,Y,MAX,用空格分隔。N是平台的数目(不包括地面),X和Y是Jimmy开始下落的位置的横竖坐标,MAX是一次下落的最大高度。接下来的N行每行描述一个平台,包括三个整数,X1[i],X2[i]和H[i]。H[i]表示平台的高度,X1[i]和X2[i]表示平台左右端点的横坐标。1 <= N <= 1000,-20000 <= X, X1[i], X2[i] <= 20000,0 < H[i] < Y <= 20000(i = 1..N)。所有坐标的单位都是米。
Jimmy的大小和平台的厚度均忽略不计。如果Jimmy恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保证问题一定有解。
Jimmy的大小和平台的厚度均忽略不计。如果Jimmy恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保证问题一定有解。
Output
对输入的每组测试数据,输出一个整数,Jimmy到底地面时可能的最早时间。
Sample Input
1 3 8 17 20 0 10 8 0 10 13 4 14 3
Sample Output
23
思路:找落到地面的最早时间,首先找到子问题的最优解。考虑当Jimmy落到一个板上的时候,他会有两种选择,向左走,向右走。我们如果知道当前的这个板左边到地面的最小值和右边到地面的最小值,则就可以求出解。每个板子从1开始进行编号,每个板子对应3个元素,左边坐标,右边坐标,以及高度坐标。每个板子的状态对应两个子问题,从板子左边到地面的最短时间和从板子右边到地面的最短时间。
状态方程:
设LeftMin(k)为k号板子的左边到地面的最小值,RightMin(k) 是k号板子的右边到地面的最小值,可以得出下列状态方程
if(k号板子左端下面有板子,编号为m){ //在m上我们有两种选择,从左边走,或者从右边走
LeftMin(k) = h(k) - h(m) + Min( LeftMin(m)+ 在m板子上走的距离,RightMin(m) + 在m号板子上走动的距离)
}
else //k号板子下面没有任何板子
{
if(k号板子高度大于max)
LeftMin(k) = 无穷大
else
LeftMin(k)= k号板子的高度;
}
同理可以求得板子右边的状态方程,则一个板到最底边的最小值就可以求出来。
代码:
Source Code
Problem: 1661 User: m68300981
Memory: 276K Time: 16MS
Language: C++ Result: Accepted
Source Code
//
// main.cpp
// HelpJimmy
//
// Created by mini on 12/18/13.
// Copyright (c) 2013 mini. All rights reserved.
//
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
using namespace std;
#define MAX_N 1000
#define MAX_NODEFINE 1000000
struct Node{
int rightPosition;
int leftPosition;
int height;
};
Node platformData[ MAX_N + 10 ];//记录每个板的信息
int rightMinTime[ MAX_N + 10 ] ;//第i个板右边到地面的时间
int leftMinTime[ MAX_N + 10 ];
int t, N, X, Y, Max;
//大到小排序
int MyCompare( const void* x, const void* y ){
Node * p1, *p2;
p1 = ( Node* )x;
p2 = ( Node* )y;
return p2 -> height - p1 ->height;
}
int MinTime( int num ,bool bLeft){
int i;
int y = platformData[ num ].height;
int x;
if( bLeft )
x = platformData[ num ].leftPosition;
else
x = platformData[ num ].rightPosition;
//找到第一个在num下面的板
for( i = num + 1; i <= N; i++ ){
if( platformData[ i ].rightPosition >= x && platformData[ i ].leftPosition <= x )
break;
}
//如果找到这个板
if( i <= N ){
if ( y - platformData[ i ].height > Max )
return MAX_NODEFINE;
}
else{ // 没有找到板
if( y > Max )
return MAX_NODEFINE;
else
return y;
}
int leftTime = y - platformData[ i ].height + x - platformData[ i ].leftPosition;
int rightTime = y -platformData[ i ].height + platformData[ i ].rightPosition - x;
if( rightMinTime[ i ] == -1 )
rightMinTime[ i ] = MinTime( i, false );
if( leftMinTime[ i ] == -1 )
leftMinTime[ i ] = MinTime( i, true );
leftTime += leftMinTime[ i ];
rightTime += rightMinTime[ i ];
if( leftTime < rightTime )
return leftTime;
else
return rightTime;
return 0;
}
int main(int argc, const char * argv[])
{
cin >> t;
while( t ){
memset( rightMinTime, -1, sizeof( rightMinTime ) );
memset( leftMinTime, -1, sizeof( leftMinTime ) );
cin>> N >> X >> Y >> Max;
platformData[ 0 ].leftPosition = X;
platformData[ 0 ].rightPosition = X;
platformData[ 0 ].height = Y;
for( int i = 1; i <= N; i++ )
cin >> platformData[ i ].leftPosition >> platformData[ i ].rightPosition >> platformData[ i ].height;
qsort( platformData, N + 1,sizeof( Node ), MyCompare);
cout << MinTime( 0, true ) << endl;
t--;
}
return 0;
}
sort版本:
//
// main.cpp
// HelpJimmy
//
// Created by mini on 12/18/13.
// Copyright (c) 2013 mini. All rights reserved.
//
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
using namespace std;
#define MAX_N 1000
#define MAX_NODEFINE 1000000
struct Node{
int rightPosition;
int leftPosition;
int height;
};
Node platformData[ MAX_N + 10 ];//记录每个板的信息
int rightMinTime[ MAX_N + 10 ] ;//第i个板右边到地面的时间
int leftMinTime[ MAX_N + 10 ];
int t, N, X, Y, Max;
//大到小排序
bool MyCompare( const Node& x, const Node& y ){
return x.height > y.height;
}
int MinTime( int num ,bool bLeft){
int i;
int y = platformData[ num ].height;
int x;
if( bLeft )
x = platformData[ num ].leftPosition;
else
x = platformData[ num ].rightPosition;
//找到第一个在num下面的板
for( i = num + 1; i <= N; i++ ){
if( platformData[ i ].rightPosition >= x && platformData[ i ].leftPosition <= x )
break;
}
//如果找到这个板
if( i <= N ){
if ( y - platformData[ i ].height > Max )
return MAX_NODEFINE;
}
else{ // 没有找到板
if( y > Max )
return MAX_NODEFINE;
else
return y;
}
int leftTime = y - platformData[ i ].height + x - platformData[ i ].leftPosition;
int rightTime = y -platformData[ i ].height + platformData[ i ].rightPosition - x;
if( rightMinTime[ i ] == -1 )
rightMinTime[ i ] = MinTime( i, false );
if( leftMinTime[ i ] == -1 )
leftMinTime[ i ] = MinTime( i, true );
leftTime += leftMinTime[ i ];
rightTime += rightMinTime[ i ];
if( leftTime < rightTime )
return leftTime;
else
return rightTime;
return 0;
}
int main(int argc, const char * argv[])
{
cin >> t;
while( t ){
memset( rightMinTime, -1, sizeof( rightMinTime ) );
memset( leftMinTime, -1, sizeof( leftMinTime ) );
cin>> N >> X >> Y >> Max;
platformData[ 0 ].leftPosition = X;
platformData[ 0 ].rightPosition = X;
platformData[ 0 ].height = Y;
for( int i = 1; i <= N; i++ )
cin >> platformData[ i ].leftPosition >> platformData[ i ].rightPosition >> platformData[ i ].height;
sort(platformData, platformData + N + 1, MyCompare);
//qsort( platformData, N + 1,sizeof( Node ), MyCompare);
cout << MinTime( 0, true ) << endl;
t--;
}
return 0;
}
qsort和sort 的区别见: 猛戳我
非递归版本,从下往上开始构造解空间
//
// main.cpp
// HelpJimmy
//
// Created by mini on 12/18/13.
// Copyright (c) 2013 mini. All rights reserved.
//
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
using namespace std;
#define MAX_N 1000
#define MAX_NODEFINE 1000000
struct Node{
int r;//右边坐标
int l;//左边坐标
int height;//高度
};
Node p[ MAX_N + 10 ];//记录每个板的信息
int rightMinTime[ MAX_N + 10 ] ;//第i个板右边到地面的时间
int leftMinTime[ MAX_N + 10 ];
int t, N, X, Y, Max;
//大到小排序
bool MyCompare( const Node& x, const Node& y ){
return x.height < y.height;
}
int MyCompareQsort( const void * x, const void * y){
Node * p1 = ( Node * )x;
Node * p2 = ( Node * )y;
if( p1 -> height < p2 -> height )
return -1;
else
return 1;
}
int main(int argc, const char * argv[])
{
cin >> t;
while( t ){
int i, j;
memset( rightMinTime, -1, sizeof( rightMinTime ) );
memset( leftMinTime, -1, sizeof( leftMinTime ) );
cin>> N >> X >> Y >> Max;
p[ 0 ].l = X;
p[ 0 ].r = X;
p[ 0 ].height = Y;
for( i = 1; i <= N; i++ )
cin >> p[ i ].l >> p[ i ].r >> p[ i ].height;
//qsort( p, N + 1,sizeof( Node ), MyCompareQsort );
sort(p, p + N + 1, MyCompare);//从小到大排序排序p数组
rightMinTime[ 0 ] = p[ 0 ].height;
leftMinTime[ 0 ] = p[ 0 ].height;
for ( i = 1; i <= N; i++ ) { //从上往下构造解空间
for ( j = i - 1; j >= 0; j-- ) {
if ( p[ i ].l >= p[ j ].l && p[ i ].l <= p[ j ].r ) {
if ( p[ i ].height - p[ j ].height > Max )
leftMinTime[ i ] = MAX_NODEFINE;
else{
leftMinTime[ i ] = p[ i ].height - p[ j ].height + min( p[ i ].l - p[ j ].l + leftMinTime[ j ], p[ j ].r - p[ i ].l + rightMinTime[ j ] );
}
break;
}
}
if( j < 0 )//左边的跳跃点没有找到下面的板,
leftMinTime[ i ] = p[ i ].height < Max ? p[ i ].height : MAX_NODEFINE;
for ( j = i - 1; j >= 0; j-- ) {
if ( p[ i ].r >= p[ j ].l && p[ i ].r <= p[ j ].r ) {
if ( p[ i ].height - p[ j ].height > Max )
rightMinTime[ i ] = MAX_NODEFINE;
else{
rightMinTime[ i ] = p[ i ].height - p[ j ].height + min( p[ i ].r - p[ j ].l + leftMinTime[ j ], p[ j ].r - p[ i ].r + rightMinTime[ j ] );
}
break;
}
}
if( j < 0 )
rightMinTime[ i ] =p[ i ].height < Max ? p[ i ].height : MAX_NODEFINE;
}
cout << min( leftMinTime[ N ], rightMinTime[ N ] ) << endl;
t--;
}
return 0;
}