题目大意:
现在有一个无权图,每个节点都是0或者1,问所有0节点到最近邻1节点的距离以及所有1节点到所有0节点的最短距离。
解题思路:
无权图最短路径很容易想到BFS,但是假如直接对每个节点都做BFS,复杂度O(N^2)会超时。另外,很容易地我们也想打一个记忆化搜索,因为有些信息是我们重复了的,比如某个0节点到1节点的最近距离,已经跑过一次了我们就不需要再跑一次。但是,问题是这里我们用BFS,我们应该很少见过用BFS打记忆化搜索的。所以记搜也否决。
这里其实我们可以反过来思考。例如我们想得到1到最近邻的0,那么我们可不可以从0出发呢,然后反向建图,那么我们需要从哪一个0出发呢?这里,很自然地我们可以建一个超级源,超级源连向所有为0的节点,同时它的边权为0,这时候跑一次BFS,我们就能得到所有节点为1的最近邻的0节点的距离了。
为什么有这个结论。我们再仔细思考,BFS是求无权最短路的。假如我们得到所有1节点到根节点(超级源)的最短距离,是不是相当于得到了所有1节点到0节点的最短距离呢。
这里有一个很好的把所有0节点拿出来建一个 超级源的思路,通过建了这个超级源,我们得到了所有1节点到0节点的最短距离。
#include <bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
vector<int> odd;
vector<int> even;
vector<vector<int>> gra(MAXN);
vector<int> ans(MAXN,0);
void bfs(vector<int> start,vector<int> end){
queue<int> q;
int dist[MAXN];
memset(dist,-1,sizeof(dist));
for(auto it:start){
dist[it]=0;
q.push(it);
}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<(int)gra[u].size();i++){
int nx=gra[u][i];
if(dist[nx]==-1){
dist[nx]=dist[u]+1;
q.push(nx);
}
}
}
for(auto it:end){
ans[it]=dist[it];
}
}
int main(){
int n;cin>>n;
for(int i=0;i<n;i++){
int t;cin>>t;
if(t&1)odd.push_back(i);
else even.push_back(i);
if(i+t<n)gra[i+t].emplace_back(i);
if(i-t>=0)gra[i-t].emplace_back(i);
}
bfs(odd,even);
bfs(even,odd);
for(int i=0;i<n;i++)cout<<ans[i]<<" ";
cout<<endl;
return 0;
}