专栏文章
题解:P5663 [CSP-J2019] 加工零件
P5663题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @miqkotsv
- 此快照首次捕获于
- 2025/12/04 06:22 3 个月前
- 此快照最后确认于
- 2025/12/04 06:22 3 个月前
年 月 日 增加了对孤立顶点的判断。
题目大意
给定一个无向图,图中每个顶点都可以生产邻接点上一个阶段的零件。给点 次询问,第 次询问顶点 生产 阶段的零件时顶点 是否能够提供原材料。
解题思路
可以将问题转化为从顶点 出发走 步是否能够停在顶点 ,可以重复走走过的顶点。
对下面左侧图进行分析,我们从顶点 出发到达顶点 ,可以发现如果步长为 等都可以到达,但是步长为 时无法到达。
如果走红色的路径从 到 ,该路径长度为 ,那么 等更大的奇数步长都能到达。因为大于 的奇数数步长我们可以通过重复路径 最终能够停留在目标顶点。如果走蓝色的路径从 到 ,该路径长度为 ,那么 等更大的偶数步长同样也能停留在目标顶点。
可将问题转换为求奇数步和偶数步的分层图最短路径问题。

解法一:分层建图
如上中间原图,我们可以采用分层建图方式,将原图拆分为 层建图。第一层为偶数层,第二层为奇数层,连边时选择偶层连奇层,奇层连偶层。
由于是无权图可以跑 BFS 获取顶点 到偶终点编号 或奇终点编号 的最短路。根据 的奇偶性选择判断 是否大于等于该条最短路的长度,如果是则输出
CPPYes 否则输出 No。#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
vector<int > G[N << 1];
int n, m, q, x, y, L, dis[N << 1];
void bfs(int st);
int main() {
cin >> n >> m >> q;
for (int i = 1; i <= m; i++) {
cin >> x >> y;
G[x].push_back(y + n); //分层建图
G[y + n].push_back(x);
G[y].push_back(x + n);
G[x + n].push_back(y);
}
bfs(1);
while (q--) {
cin >> x >> L;
if (G[x].size() == 0) cout << "No\n";
else {
int res = dis[x + (L & 1) * n];
if (res <= L) cout << "Yes\n";
else cout << "No\n";
}
}
return 0;
}
void bfs(int st) {
memset(dis, 0x3f, sizeof dis);
queue<int> q;
q.push(st);
dis[st] = 0;
while (q.size()) {
int hx = q.front();
q.pop();
for (auto to : G[hx]) {
if (dis[to] > dis[hx] + 1) {
dis[to] = dis[hx] + 1;
q.push(to);
}
}
}
}
解法二:拆分点权
本质上与解法一相同,不过不用去建分层图而是将点权拆分为两份。在计算走到当前顶点的最短路时,偶距离由邻接点的奇距离更新,同样奇距离由偶距离更新。

#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
vector<int> G[N];
int n, m, q, x, y, L, dis[N][2], vis[N];
void bfs(int st) {
queue<int> q;
q.push(st);
memset(dis, 0x3f, sizeof dis);
dis[st][0] = 0;
vis[st] = 1;
//vis标记是否在队列中,优化避免一个顶点重复入队
while (q.size()) {
int hx = q.front();
q.pop();
vis[hx] = 0;
for (auto to : G[hx]) {
//奇偶最短路交替更新
if (dis[to][0] > dis[hx][1] + 1) {
dis[to][0] = dis[hx][1] + 1;
if (!vis[to]) q.push(to), vis[to] = 1;
}
if (dis[to][1] > dis[hx][0] + 1) {
dis[to][1] = dis[hx][0] + 1;
if (!vis[to]) q.push(to), vis[to] = 1;
}
}
}
}
int main() {
cin >> n >> m >> q;
for (int i = 1; i <= m; i++) {
cin >> x >> y;
G[x].push_back(y); //无向图双向存图
G[y].push_back(x);
}
bfs(1);
while (q--) {
cin >> x >> L;
if (G[x].size() == 0) cout << "No\n";
else {
int res = dis[x][L & 1];
if (res <= L) cout << "Yes\n";
else cout << "No\n";
}
}
return 0;
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...