奇怪的电梯
题意:大楼的每一层楼都可以停电梯,每层楼均有一个数字,电梯只有两个按钮,相应的按钮:上和 下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮会失灵。例如,一楼的数字为3,则按“上”可以到4楼,按“下”是不起作用的,因为没有-2楼。
输入
输入共有二行,第一行为三个用空格隔开的正整数,表示N,A,B(1≤N≤200, 1≤A,B≤N),第二行为N个用空格隔开的正整数,表示Ki。
输出
输出仅一行,即最少按键次数,若无法到达,则输出-1。
样例输入
5 1 5
3 3 1 2 5
样例输出
3
代码分析与讲解都在注释里,采用DP(动态规划来解答)
为了动态分配内存,采用STL的vector容器来解答,也可以简单的用数组来实现
#include <iomanip>
#include <iostream>
#include <vector>
using namespace std;
inline long long min(long long a, long long b) { return (a>b ? b : a); }
int main()
{
vector<vector<long long>> dp;//保存电梯动态规划所有解,dp[i][j]表示从第i层到第j层最少按得次数
vector<long long> k;//保存电梯每一层可以上升或者下降的层数
int n = 0;//n层电梯
int start = 0;//开始层
int end = 0;//目的层
int tmp;
cin >> n >> start >> end;
for (int i = 0; i <= n; i++)
{
vector<long long> v;
for (int j = 0; j <= n; j++)
{
if (i == j) v.push_back(0);//因为i == j ,所以dp[i][j]层不用按下,即0次
v.push_back(INT_MAX);//INT_MAX为系统自带最大值,两个INT_MAX相加会越界,所以采用存储long long类型
}
dp.push_back(v);
}
k.push_back(0);//为了方便理解,先push一个0,使得下标从1开始
for (int i = 1; i <= n; i++)
{
cin >> tmp;
k.push_back(tmp);
}
//首先初始化电梯按下1次即可到达的层数
for (int i = 1; i <= n; i++)
{
if (i + k[i] <= end)
{
dp[i][i + k[i]] = 1;
}
if (i - k[i] >= 1)
{
dp[i][i - k[i]] = 1;
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
for (int p = 1; p <= n; p++)
{
//电梯从i到j层就是从i到p层加上从p到j层的次数,去最小值,动态规划
dp[i][j] = min(dp[i][j], dp[i][p]+dp[p][j]);
}
}
}
/*
//输出最终数组答案,
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (dp[i][j] == INT_MAX) //为了方便观察,将不能到达的值输出为-1
{
cout << setw(5) << -1;
}
else
{
cout << setw(5) << dp[i][j];
}
}
cout << endl;
}
*/
if (dp[start][end] == INT_MAX) //为了方便观察,将不能到达的值输出为-1
{
cout << -1;
}
else
{
cout << dp[start][end];
}
return 0;
}
代码分析与讲解都在注释里,采用BFS解答
为了动态分配内存,采用STL的vector容器和queue队列容器来解答,也可以简单的用数组来实现
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int main()
{
queue<int> q; //BFS 实现用队列
vector<int> v; //保存每层按钮上的数值
vector<int> f; //到达每层最少的按键次数
vector<bool> flag;//标记值,表示每层是否被访问过,true代表访问过
int n;
int start, end;//开始层和结束层
int tmp;
cin >> n >> start >> end;
v.push_back(0);//方便起见,下标从1开始
f.push_back(0);
flag.push_back(false);
for (int i = 1; i <= n; i++)
{
cin >> tmp;
v.push_back(tmp);
if(i == start)
f.push_back(0);//初始化,start层开始为按0次,其余层为-1次
else
f.push_back(-1);
flag.push_back(false);
}
q.push(start);
while (!q.empty()&& !flag.at(q.front()))//队列不为空,切第q.front()层没有被访问过
{
flag.at(q.front()) = true;
int next = q.front() + v.at(q.front());
if (next <= n) //上楼
{
q.push(next);
f.at(next) = f.at(q.front()) + 1;//记下到达每层最少的按键次数
if (next == end) //找到end层,退出while循环
{
break;
}
}
next = q.front() - v.at(q.front());
if (next >= 1)//下楼
{
q.push(next);
f.at(next) = f.at(q.front()) + 1;
if (next == end)//找到end层,退出while循环
{
break;
}
}
q.pop();
}
cout << f.at(end) << endl;
return 0;
}