您的位置:首页 > 编程语言 > C语言/C++

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

2012-05-14 20:33 232 查看
问题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;
}


好了 最短路径告一段落
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  path file 算法