题解:P14128 [SCCPC 2021] Spicy Restaurant
题意简述
给定一张有 \(n\) 个带权的点和 \(m\) 条无向边,进行 \(q\) 次询问,第 \(i\) 次询问距离点 \(p_i\) 最近且权值不超过 \(a_i\) 的点与 \(p_i\) 之间有几条边。
思路
显然要用到最短路。根据数据范围可以发现,所询问的 \(p_i\) 和 \(a_i\) 最多不超过 \(10^7\) 种,容易想到预处理答案数组。
对于每一个点,可以用 BFS 求出最近的且权值不超过 \(a_i\) 的点,然后对于 \([1,100]\) 中每一个 \(a_i\) 都预处理该点的答案,就可以做出来了。
预处理时只用注意以下几点即可:
- 初始化答案数组为无穷大,如果预处理后仍未无穷大以表示无法到达;
- 对于权值为 \(a_i\) 时的预处理,最小距离最大也不超过 \(a_i-1\) 时的最小距离,因为不超过 \(a_i-1\) 则必然不会超过 \(a_i\) 的值。
然后就没什么值得注意的了。放代码。
AC 代码:
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const int N=100005,W=105;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
int n,m,T,dis[N][W];
int w[N];
vector<int>g[N];
void bfs(int k) {// k 是辣度值
queue<int>q;
while(!q.empty())q.pop();
for(int i=1;i<=n;i++) {
dis[i][k]=dis[i][k-1];// 对应第二条
}
for(int i=1;i<=n;i++) {
if(w[i]==k) {
dis[i][k]=0;
q.push(i);
}
}
while(!q.empty()) {
int u=q.front();
q.pop();
for(int v:g[u]) {
if(dis[v][k]>dis[u][k]+1) {
dis[v][k]=dis[u][k]+1;
q.push(v);
}
}
}
}
void init() {
memset(dis,inf,sizeof(dis));
for(int i=1;i<=100;i++)bfs(i);
}
int main() {
ios;cin>>n>>m>>T;
for(int i=1;i<=n;i++)
cin>>w[i];
int u,v;
for(int i=1;i<=m;i++) {
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
init();// 预处理
int p,a;
while(T--) {
cin>>p>>a;
if(dis[p][a]==inf)cout<<"-1\n";// 无法到达
else cout<<dis[p][a]<<'\n';
}
return 0;
}
本文来自博客园,作者:Circle_Table,转载请注明原文链接:https://www.cnblogs.com/Circle-Table/articles/19177435

浙公网安备 33010602011771号