洛谷:link
题目比较水深搜,广搜,动态规划都给它安排上
dpf
#include <bits/stdc++.h>
using namespace std;
int N,A,B;
int a[220];
int vis[220];
int ans = 0x3f3f3f3f;
void dfs(int x,int step)
{
if(step>=ans) return ;//剪枝
if(x==B)
{
ans = min(step,ans);
}
vis[x]=1;
if(x+a[x]<=N&&!vis[x+a[x]])
//一开始我的写法是先将这个点记个访问再dfs的但第8个wrong就是不是最优解
//问题所在就是当我回溯的时候这个点依然被标记了,造成回溯没有达到我要的效果
dfs(x+a[x],step+1);
if(x-a[x]>=1&&!vis[x-a[x]])
dfs(x-a[x],step+1);
vis[x] = 0;//回溯
}
int main()
{
ios::sync_with_stdio(false);
cin >> N >> A >> B;
for (int i = 1; i <= N; i++)
cin >> a[i];
dfs(A,0);
if(ans ==0x3f3f3f3f)
{
cout<<-1;
}
else cout<<ans;
return 0;
}
bfs
#include <bits/stdc++.h>
using namespace std;
int N,A,B;
int a[220];
int ans = INT_MAX;
struct g{
int step,cur;
bool operator<(const g&rhs) const
{
if(step==rhs.step)
return cur<rhs.cur;
return step<rhs.step;
}
};
int main()
{
ios::sync_with_stdio(false);
cin >> N >> A >> B;
for (int i = 1; i <= N; i++)
cin >> a[i];
queue<g> q;
set<int> s;//注意一开始我用的g然后timeexceed三个点
g temp;
q.push(g{0,A});
while(!q.empty())
{
temp = q.front();
if(temp.cur==B)
break;
q.pop();
int right = temp.cur+a[temp.cur];
int left= temp.cur-a[temp.cur];
if(right<=N&&!s.count(right))
{
q.push(g{temp.step+1,right});
s.insert(right);
}
if(left>=1&&!s.count(left))
{
q.push(g{temp.step+1,left});
s.insert(left);
}
}
if(temp.cur == B)
cout<<temp.step;
else cout<<-1;
return 0;
}
dp
dp[i][j] 表示阶段i或者说按的次数内,j楼层是否到达
因此我们得出转移方程dp[i][j] == 1
这个点现在到达了,那么下个可以到达的点为
dp[i+1][j-a[j]] = dp[i+1][j+a[j]] = 1;
还有必须要加上个特判A==B的情况别问我怎么知道的…
#include <bits/stdc++.h>
using namespace std;
int dp[2010][220];
int a[220];
int main()
{
ios::sync_with_stdio(false);
int N, A, B;
cin >> N >> A >> B;
if (A == B)
{
cout << 0;
return 0;
}
dp[0][A] = 1;
for (int i = 1; i <= N; i++)
cin >> a[i];
for (int i = 0; i <= 2000; i++)
{
for (int j = 1; j <= N; j++)
{
if (dp[i][j])
{
if (j + a[j] <= N)
dp[i + 1][j + a[j]] = 1;
if (j - a[j] >= 1)
dp[i + 1][j - a[j]] = 1;
if (dp[i + 1][B])
{
cout << i + 1;
return 0;
}
}
}
}
cout << -1;
return 0;
}