牛客网 送外卖 BFS

链接:https://ac.nowcoder.com/acm/problem/13224
来源:牛客网

题目描述

n 个小区排成一列,编号为从 0 到 n-1 。一开始,美团外卖员在第0号小区,目标为位于第 n-1 个小区的配送站。
给定两个整数数列 a[0]~a[n-1] 和 b[0]~b[n-1] ,在每个小区 i 里你有两种选择:
1) 选择a:向前 a[i] 个小区。
2) 选择b:向前 b[i] 个小区。

把每步的选择写成一个关于字符 ‘a’ 和 ‘b’ 的字符串。求到达小区n-1的方案中,字典序最小的字符串。如果做出某个选择时,你跳出了这n个小区的范围,则这个选择不合法。
• 当没有合法的选择序列时,输出 “No solution!”。
• 当字典序最小的字符串无限长时,输出 “Infinity!”。
• 否则,输出这个选择字符串。

字典序定义如下:串s和串t,如果串 s 字典序比串 t 小,则
• 存在整数 i ≥ -1,使得∀j,0 ≤ j ≤ i,满足s[j] = t[j] 且 s[i+1] < t[i+1]。
• 其中,空字符 < ‘a’ < ‘b’。

输入描述:

输入有 3 行。
第一行输入一个整数 n (1 ≤ n ≤ 10^5)。
第二行输入 n 个整数,分别表示 a[i] 。
第三行输入 n 个整数,分别表示 b[i] 。
−n ≤ a[i], b[i] ≤ n

输出描述:

输出一行字符串表示答案。

解题思路:如果用bfs从下标为0每次移动至另一状态判断是否能到达终点,其实现难点在于如何判断是否会Infinity,因为不同的走法其路线不同走过的顶点也不同;用dfs+回溯可以AC 
参考;用bfs求解思路:反向建图,从下标n-1(实现时下标从1-n)判断是否有到达0的路径,在经过的节点上标记。接着从下标为0每次判断下一步是否在可行路径的节点上,且如果重复
到达同一节点则Infinity。
实现代码:
#include<iostream>
#include<string> 
#include<vector>
#include<queue>
using namespace std;

const int Max_N = 1e5+10;

int n;
int a[Max_N], b[Max_N];
vector<int> graph[Max_N];
bool visited1[Max_N], visited2[Max_N]; //反向、正向经过的节点 

void bfs(int s);
void solve();

int main()
{
    cin>>n;
    for( int i=1; i<=n; i++ )
    {
        cin>>a[i];
        int x = i + a[i];
        if( 1<=x&&x<=n )    graph[x].push_back(i);//反向建图 
    }
    for( int i=1; i<=n; i++ )
    {
        cin>>b[i];
        int x = i + b[i];
        if( 1<=x&&x<=n )    graph[x].push_back(i);//反向建图 
    }
    
    solve();
    
    return 0;
}

void bfs(int s)
{
    queue<int> que;
    que.push(s);
    visited1[s] = true; //先true在push 防止超时 
    while( !que.empty() )
    {
        int v = que.front(); que.pop();//v 当前节点 
        int cize = graph[v].size();
        for( int i=0; i<cize; i++ )
        {
            int u = graph[v][i];
            if( !visited1[u] )
            {
                visited1[u] = true;
                que.push(u);    //可行路径上的节点 
            }    
        }    
    }    
}

void solve()
{
    bfs(n);
    
    if( !visited1[1] ) //没有从n到1的路径 
    {
        cout<<"No solution!"<<endl;
        return;
    }
    
    bool infinity = false;
    string ans = "";
    int x = 1;
    while( x!=n )
    {
        int nx = x + a[x];
        if( 1<=nx&&nx<=n && visited1[nx] )
        {
            if( !visited2[nx] )
            {//没有重复(环路) 
                visited2[nx] = true;
                ans += "a";
                x = nx;
            }
            else//重复路径 
                infinity = true;
        }
        else
        {
            nx = x + b[x];
            if( 1<=nx&&nx<=n && visited1[nx] )//可以走 
            {
                if( !visited2[nx] )
                {//没有重复(环路) 
                    visited2[nx] = true;
                    ans += "b";
                    x = nx;
                }
                else
                    infinity = true;
            }
        }
        if( infinity )    break;
    }
    if( infinity )    cout<<"Infinity!"<<endl;
    else            cout<<ans<<endl;
}
posted @ 2021-04-10 14:47  代码改变头发  阅读(139)  评论(0编辑  收藏  举报