P1135 奇怪的电梯
\(bfs\)
const int N=210;
int k[N];
int dist[N];
int n,a,b;
inline bool check(int x)
{
return x>=1 && x<=n;
}
int bfs()
{
memset(dist,-1,sizeof dist);
queue<int> q;
q.push(a);
dist[a]=0;
while(q.size())
{
int t=q.front();
q.pop();
if(t == b) return dist[b];
if(check(t+k[t]) && dist[t+k[t]] == -1)
dist[t+k[t]]=dist[t]+1,q.push(t+k[t]);
if(check(t-k[t]) && dist[t-k[t]] == -1)
dist[t-k[t]]=dist[t]+1,q.push(t-k[t]);
}
return -1;
}
int main()
{
cin>>n>>a>>b;
for(int i=1;i<=n;i++) cin>>k[i];
int t=bfs();
cout<<t<<endl;
//system("pause");
}
\(dfs+剪枝\)
剪枝策略:
- 最优性剪枝
- 记忆化剪枝:当重复到达一个楼层时,相当于在图上走了一个环,此时路径必然不是最短,已没有继续向深层搜索的必要
另由于第一次访问到b点不一定是最短路径,所以需要回溯,一旦发现有更短的路径则更新
const int N=210;
int k[N];
int vis[N];
int n,a,b;
int ans=INF;
inline bool check(int x)
{
return x>=1 && x<=n;
}
void dfs(int u,int x)
{
if(u > ans) return;
if(x == b) ans=u;
if(check(x+k[x]) && !vis[x+k[x]])
{
vis[x+k[x]]=1;
dfs(u+1,x+k[x]);
vis[x+k[x]]=0;
}
if(check(x-k[x]) && !vis[x-k[x]])
{
vis[x-k[x]]=1;
dfs(u+1,x-k[x]);
vis[x-k[x]]=0;
}
}
int main()
{
cin>>n>>a>>b;
for(int i=1;i<=n;i++) cin>>k[i];
vis[a]=1;
dfs(0,a);
if(ans == INF) cout<<-1<<endl;
else cout<<ans<<endl;
//system("pause");
}
- 若节点需要访问多次,这时候回溯需要取消标记,不然无法访问了
- 若节点只访问一次,就不需要取消标记
- 因题而异