|
Posted on 2010-08-15 16:19 MiYu 阅读(659) 评论(0) 编辑 收藏 引用 所属分类: ACM ( 最短路 )
MiYu原创, 转帖请注明 : 转载自 ______________白白の屋
题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=1548 题目描述:
A strange lift Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2641 Accepted Submission(s): 944
Problem Description There is a strange lift.The lift can stop can at every floor as you want, and there is a number Ki(0 <= Ki <= N) on every floor.The lift have just two buttons: up and down.When you at floor i,if you press the button "UP" , you will go up Ki floor,i.e,you will go to the i+Ki th floor,as the same, if you press the button "DOWN" , you will go down Ki floor,i.e,you will go to the i-Ki th floor. Of course, the lift can't go up high than N,and can't go down lower than 1. For example, there is a buliding with 5 floors, and k1 = 3, k2 = 3,k3 = 1,k4 = 2, k5 = 5.Begining from the 1 st floor,you can press the button "UP", and you'll go up to the 4 th floor,and if you press the button "DOWN", the lift can't do it, because it can't go down to the -2 th floor,as you know ,the -2 th floor isn't exist. Here comes the problem: when you is on floor A,and you want to go to floor B,how many times at least he havt to press the button "UP" or "DOWN"?
Input The input consists of several test cases.,Each test case contains two lines. The first line contains three integers N ,A,B( 1 <= N,A,B <= 200) which describe above,The second line consist N integers k1,k2, .kn. A single 0 indicate the end of the input.
Output For each case of the input output a interger, the least times you have to press the button when you on floor A,and you want to go to floor B.If you can't reach floor B,printf "-1".
Sample Input 5 1 5 3 3 1 2 5 0
Sample Output 3
题目分析:
这题又是一个标准的 Dijkstra 算法的题目 ( 最短路 ). 要说难度吗? 对我而言吧, 就是 图的生成. 刚开始做的时候自己想复杂了, 以为从不同的楼层开始, 就有不同的走法, 所以开始的时候写循环没写对, 就写成了递归. 结果很杯具的 STACK_OVERFLOW........ 在 AMB 神牛的指点发现, 原来是自己想复杂了, 只需要计算出每一个楼层的 上楼 和 下楼就可以了, 当然, 要注意是否越界. 图生成后, 当然就是 DIJKSTRA了. 闲来无事, 又复制一遍 : Dijkstra算法的基本思路是: 假设每个点都有一对标号 (dj, pj),其中dj是从起源点s到点j的最短路径的长度 (从顶点到其本身的最短路径是零路(没有弧的路),其长度等于零); pj则是从s到j的最短路径中j点的前一点。求解从起源点s到点j的最短路径算法的基本过程如下: 1) 初始化。起源点设置为:① ds=0, ps为空;② 所有其他点: di=∞, pi=?;③ 标记起源点s,记k=s,其他所有点设为未标记的。 2) 检验从所有已标记的点k到其直接连接的未标记的点j的距离,并设置:
dj=min[dj, dk+lkj]
式中,lkj是从点k到j的直接连接距离。
3) 选取下一个点。从所有未标记的结点中,选取dj 中最小的一个i:
di=min[dj, 所有未标记的点j]
点i就被选为最短路径中的一点,并设为已标记的。
4) 找到点i的前一点。从已标记的点中找到直接连接到点i的点j*,作为前一点,设置:i=j*
5) 标记点i。如果所有点已标记,则算法完全推出,否则,记k=i,转到2) 再继续。
代码如下:
#include <iostream> using namespace std; const int MAX = 200; const int INF = 0x7FFFFFF; int N,A,B; int g[MAX+1][MAX+1]; int hash[MAX+1]; int path[MAX+1]; int K[MAX+1]; int Dijkstra ( int beg , int end ) { path[beg] = 0; hash[beg] = false; while ( beg != end ) { int m = INF, temp; for ( int i = 1; i <= N; ++ i ) { if ( g[beg][i] != INF ) path[i] = min ( path[i], path[beg] + g[beg][i] ); if ( m > path[i] && hash[i] ) { m = path[i]; temp = i; } } beg = temp; if ( m == INF ) break; hash[beg] = false; } if ( path[end] == INF ) return -1; return path[end]; }
int main () { while ( scanf ( "%d%d%d", &N, &A, &B ) , N ) { for ( int i = 0; i <= MAX; ++ i ) { hash[i] = true; path[i] = INF; for ( int j = 0; j <= MAX; ++ j ) { g[i][j] = INF; } } for ( int i = 1; i <= N; ++ i ) { scanf ( "%d",&K[i] ); } for ( int i = 1; i <= N; ++ i ) { if ( i + K[i] <= N ) g[ i ][ i + K[i] ] = 1; if ( i - K[i] >= 1 ) g[ i ][ i - K[i] ] = 1; } cout << Dijkstra ( A, B ) << endl; } return 0; }
SO 代码:
#include <iostream> using namespace std; const int MAX = 200; const int INF = 0x7FFFFFF; bool UP = true; bool DOWN = false; int N,A,B; int g[MAX+1][MAX+1]; int hash[MAX+1]; int path[MAX+1]; int K[MAX+1];
int Dijkstra ( int beg , int end ) { path[beg] = 0; hash[beg] = false; while ( beg != end ) { int m = INF, temp; for ( int i = 1; i <= N; ++ i ) { if ( g[beg][i] != INF ) path[i] = min ( path[i], path[beg] + g[beg][i] ); if ( m > path[i] && hash[i] ) { m = path[i]; temp = i; } } beg = temp; if ( m == INF ) break; hash[beg] = false; } if ( path[end] == INF ) return -1; return path[end]; }
bool setGraph ( int n, bool flag ) { if ( flag ) { if ( n + K[n] <= N ) { g[ n ][ n + K[n] ] = 1; setGraph ( n + K[n], UP ); setGraph ( n + K[n], DOWN ); } } else { if ( n - K[n] >= 1 ) { g[ n ][ n - K[n] ] = 1; setGraph ( n - K[n], UP ); setGraph ( n - K[n], DOWN ); } } return true; } int main () { while ( scanf ( "%d%d%d", &N, &A, &B ) , N ) { for ( int i = 0; i <= MAX; ++ i ) { hash[i] = true; path[i] = INF; for ( int j = 0; j <= MAX; ++ j ) { g[i][j] = INF; } } for ( int i = 1; i <= N; ++ i ) { scanf ( "%d",&K[i] ); } for ( int i = 1; i <= N; ++ i ) { setGraph ( i, UP ); setGraph ( i, DOWN ); } cout << Dijkstra ( A, B ) << endl; } return 0; }
|