题解:P14128 [SCCPC 2021] Spicy Restaurant
题目大意
给出一个
一共 -1。
分析
观察到
又很容易观察到
边权都为
代码细节
其实本题的 BFS 是多源 BFS,因为要从所有符合条件的点出发,直接将所有点同时入队即可:
queue<pair<int,int> > q;
//队列,pair 的第一关键字为节点编号,第二关键字为路径长度
for (int i=1;i<=n;i++){
vis[i]=false;//初始化 vis 数组
if (a[i]<=mx){//如果节点辣度能被接受
vis[i]=true;
q.push({i,0});
dp[i][mx]=0;
//从此节点出发进行 BFS
}
}
最后提醒一下,若使用链式前向星存图一定要开双倍空间(双向边)。
AC code:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
//注意:要开双倍空间(双向边)
int vtx[N],nxt[N],hed[N],tot;//链式前向星数组
int n,m,q,a[N],dp[N][105];
//如题所述,不同的是 a[i] 存的是点权,dp[i][j] 存的是答案(位于第 i 个点能接受的最大辣度为 j 时的答案)
bool vis[N];
//BFS 是否访问过
inline void addedge(int u,int v){//链式前向星存图(建边)
vtx[++tot]=v;
nxt[tot]=hed[u];
hed[u]=tot;
}
inline void add(int u,int v){//建双向边
addedge(u,v);
addedge(v,u);
}
inline void bfs(int mx){//核心 BFS
queue<pair<int,int> > q;
//队列,pair 的第一关键字为节点编号,第二关键字为路径长度
for (int i=1;i<=n;i++){
vis[i]=false;//初始化 vis 数组
if (a[i]<=mx){//如果节点辣度能被接受
vis[i]=true;
q.push({i,0});
dp[i][mx]=0;
//从此节点出发进行 BFS
}
}
while (!q.empty()){
int x=q.front().first;
int s=q.front().second;//最短路
q.pop();
//弹出队首元素
for (int j=hed[x];j;j=nxt[j]){//链式前向星遍历
int y=vtx[j];
if (!vis[y]){
vis[y]=true;
q.push({y,s+1});
dp[y][mx]=s+1;
//入队,继续更新答案
}
}
}
}
int main(){
cin>>n>>m>>q;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1,x,y,z;i<=m;i++){
cin>>x>>y;
add(x,y);
}//以上都是输入
//把 dp 数组初始化为极大值
memset(dp,0x7f,sizeof(dp));
//预处理所有辣度并求最短路
for (int i=1;i<=100;i++) bfs(i);
while (q--){
int p,w;cin>>p>>w;
//直接输出即可,注意要判断无解情况,即超过 n 次都到不了
cout<<(dp[p][w]>n?-1:dp[p][w])<<'\n';
}
return 0;
}