【Optimal Path】Lift.cpp 奇怪的电梯

来源:互联网 发布:山东邦和康欣淘宝网 编辑:程序博客网 时间:2024/05/21 06:56

问题2: 奇怪的电梯

( lift.pas )

 

要求:此题用floyd和dijstra算法分别完成。

 

问题描述:

呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第i层楼(1<=i<=N)上有一个数字Ki(0<=Ki<=N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:3 3 1 2 5代表了Ki(K1=3,K2=3,……),从一楼开始。在一楼,按“上”可以到4楼,按“下”是不起作用的,因为没有-2楼。那么,从A楼到B楼至少要按几次按钮呢?

 

输入格式:lift.in

输入文件共有二行,第一行为三个用空格隔开的正整数,表示N,A,B(1≤N≤200, 1≤A,B≤N),第二行为N个用空格隔开的正整数,表示Ki。

 

输出格式:lift.out

输出文件仅一行,即最少按键次数,若无法到达,则输出-1。

 

样例

lift.in

lift.out

5 1 5

3 3 1 2 5

3

 



#include <cstdio>#include <iomanip>#include <cstdlib>#include <cstring>#define min(a, b) (a < b ? a : b)#define fi "lift.in"#define fo "lift.out"namespace Solve{  int N; int A; int B;  int F[200][200];  void Init_file();  void Read_data();  void Work();  void solve();}void Solve::Init_file(){  freopen(fi, "r", stdin);  freopen(fo, "w", stdout);}void Solve::Read_data(){  scanf("%d%d%d", &N, &A, &B);  for(int i = 0; i < N; i++)  {    for(int j = 0; j < N; j++)          F[i][j] = 100000;    F[i][i] = 0;  }  for(int i = 0; i < N; i++)  {    int x;    scanf("%d", &x);    if (i + x < N) F[i][i + x] = 1;    if (i - x >= 0) F[i][i - x] = 1;  }}void Solve::Work(){  for(int k = 0; k < N; k++)    for(int i = 0; i < N; i++) if(i != k)      for(int j = 0; j < N; j++) if (k != j && i != j)      {        F[i][j] = min(F[i][j], F[i][k] + F[k][j]);      }    if (F[A - 1][B - 1] == 100000)  printf("%d", -1);  else printf("%d", F[A - 1][B - 1]);}void Solve::solve(){  Init_file();  Read_data();  Work();}int main(){  Solve::solve();  return 0;}

然后第二种方法 Dijkstra 还是先建图 每次选一个离dist最小的点加入路径中 再更新其他点的dist值

最后输出Dist[B] 注意dist[i]的初值是Map[A][i]

代码如下

#include <cstdio>#include <iomanip>#include <cstdlib>#include <cstring>#define MAX 1000000#define fi "lift.in"#define fo "lift.out"namespace Solve{  int N; int A; int B;  int Min;  int k;  int dist[500];  bool Vst[500];  int Map[200][200];  void Init_file();  void Read_data();  void Work();  void solve();}void Solve::Init_file(){  freopen(fi, "r", stdin);  freopen(fo, "w", stdout);}void Solve::Read_data(){  scanf("%d%d%d", &N, &A, &B);  for(int i = 1; i <= N; i++)  {    for(int j = 1; j <= N; j++)      Map[i][j] = MAX;    Map[i][i] = 0;  }  for(int i = 1; i <= N; i++)  {    int x;    scanf("%d", &x);    if (x == 0) continue;    if (i + x <= N) Map[i][i + x] = 1;    if (i - x >= 1) Map[i][i - x] = 1;   }}void Solve::Work(){  for(int i = 1; i <= N; i++)  {    dist[i] = Map[A][i];  }  Vst[A] = 1;  for(int i = 1; i <= N - 1; i++) //共标记 N - 1 个点  {    //找一个dist最小未被标记的节点K    int k;    Min = MAX;     for(int j = 1; j <= N; j++)    {      if (!Vst[j] && Min > dist[j])      {        Min = dist[j];        k = j;      }    }    if (k == 0) return;    Vst[k] = 1;    for(int j = 1; j <= N; j++)    {      if (!Vst[j] && dist[j] > dist[k] + Map[k][j])        dist[j] = Map[k][j] + dist[k];    }  }  if (dist[B] == MAX) printf("%d", -1);  else printf("%d", dist[B]);}void Solve::solve(){  Init_file();  Read_data();  Work();}int main(){  Solve::solve();  return 0;}

那么 下面是最常用也是最好记的方法 笔者极力推荐的 SPFA 关于这个算法的背景笔者就不多介绍了

SPFA 在形式上和宽度优先搜索非常类似
不同的是宽度优先搜索中一个点出了队列就不可能重新进入队列
但是SPFA中一个点可能在出队列之后再次被放入队列,也就是一个点改进过其它的点之后,过了一段时间可能本身被改进,于是再次用来改进其它的点
这样反复迭代下去
………………就出答案了
SPFA很快……

#include <cstdio>#include <iomanip>#include <cstdlib>#include <cstring>#define min(a, b) (a < b ? a : b)#define fi "lift.in"#define fo "lift.out"namespace Solve{  int N; int A; int B;  int L; int R;  int Map[500][500];  bool Vst[500];  int dist[500];  int queue[500];  int Father[500];  void Init_file();  void Read_data();  void Work();  void solve();}void Solve::Init_file(){  freopen(fi, "r", stdin);  freopen(fo, "w", stdout);}void Solve::Read_data(){  scanf("%d%d%d", &N, &A, &B);  for(int i = 0; i < N; i++)  {    for(int j = 0; j < N; j++) Map[i][j] = 987654321;    Map[i][i] = 0;  }  for(int i = 0; i < N; i++)  {    int x;    scanf("%d", &x);    if (x == 0) continue;    if (i + x < N) Map[i][i + x] = 1;    if (i - x >= 0) Map[i][i - x] = 1;  }}void Solve::Work(){//  memset(dist, 0x3f, sizeof(dist));for(int i = 0; i < N; i++){  dist[i] = 98765432;}  L = R = 0;  dist[A - 1] = 0;  queue[R] = A - 1;  Vst[A - 1] = 1;//  printf("%d ", queue[0]);  while(L <= R)  {    int now = queue[L];  //  printf("%d ", now);    Vst[now] = 0;    for(int j = 0; j < N; j++)    {      if(Map[now][j])      {        if (dist[j] > dist[now] + Map[now][j])        {          dist[j] = dist[now] + Map[now][j];          Father[j] = now;          if (!Vst[j])          {            queue[++R] = j;            Vst[j] = 1;          }        }      }    }    L++;  }  if (dist[B - 1] != 98765432)  printf("%d", dist[B - 1]);  else printf("%d", -1);}void Solve::solve(){  Init_file();  Read_data();  Work();}int main(){  Solve::solve();  return 0;}

好了 最短路径告一段落

原创粉丝点击