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");
}
  • 若节点需要访问多次,这时候回溯需要取消标记,不然无法访问了
  • 若节点只访问一次,就不需要取消标记
  • 因题而异
posted @ 2020-09-14 17:12  Dazzling!  阅读(177)  评论(0编辑  收藏  举报