【笔记】洛谷P5663 [CSP-J 2019] 加工零件(奇偶最短路)

题意

给出一张结点数为 n、边数为 m 的无向图。对于 q 个询问,输出所询问的顶点 a 与顶点 1 间,是否有一条长度为 L 的路径。

为什么询问的是顶点 a 与顶点 1 间,是否有一条长度为L的路径?

题目说“如果 x 号工人想生产一个被加工到第 L(L>1) 阶段的零件,则所有与 x 号工人有传送带直接相连的工人,都需要生产一个被加工到第 L−1 阶段的零件”,询问“ 1 号工人是否需要给别人提供原材料”。

当 L=1 时:

a 需要生产第一阶段零件 ⟺ a 的邻居需要提供原材料,1 需要给 a 提供原材料 ⟺ 1 是 a 的邻居
∴ 如果 1 要给 a 提供原材料,则 1 和 a 间必然存在长度为 1 的路径

当 L=2 时:

a 需要生产第二阶段零件 ⟺ a 的邻居需要生产第一阶段零件 ⟺ a 的邻居的邻居需要提供原材料,1 需要给 a 提供原材料 ⟺ 1 是 a 的邻居的邻居
∴ 如果 1 要给 a 提供原材料,则 1 和 a 间必然存在长度为 2 的路径

不难发现,当 L=x(x≥1) 时:

a 需要生产第 x 阶段零件
∴ 如果 1 要给 a 提供原材料,则 1 与 a 间必然存在长度为 x 的路径

题目即求 1 与 a 间是否存在长度为 L 的路径。

思路

根据朴素的常识,在相邻的两个顶点上来回移动的话,可以为当前路径增加偶数长度。如下图,1 至 3 的路径长度可以是 2(1→2→3)、4(1→2→1→2→3)、6(1→2→1→2→1→2→3)……
image
可以把 L 理解为从 a 走到 1 的步数,即使奇偶相同,只要步数不够多也无法到达,所以若计算出 1 和 a 最短路径长度为奇数 x,则当 L 恰为大于等于 x 的奇数时,1 需要给 a 提供原材料;同理,若计算出 1 和 a 最短路径长度为偶数 x,则当 L 恰为大于等于 x 的偶数时,1 需要给 a 提供原材料。算法思路如下。

  1. 计算每个顶点到 1 的奇偶最短路
  2. 如果 L 是奇数,则检查 a 到 1 的奇最短路是否小于等于 L;偶数同理
  3. 根据检查结果输出

代码

#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,q;
int ji[100005],ou[100005]; // ji[i]=从顶点 i 到顶点 1 的奇数最短路,ou 同理
queue<pair<int,int> > que; // BFS用的队列;另外“>>”间要加空格,不然可能被解析为右移运算符
int main(){
    scanf("%d%d%d",&n,&m,&q);
    vector<vector<int> > a(n+1); // 邻接表,用矩阵内存会炸
    int u,v;
    for(int i=0;i<m;i++){
        scanf("%d%d",&u,&v);
        a[u].push_back(v);
        a[v].push_back(u);
    }
    memset(ji,0x3f,sizeof(ji)); // 初始化为最大值,表示无法到达
    memset(ou,0x3f,sizeof(ou));
    que.push(make_pair(1,0)); // (编号,步数)
    ou[1]=0; // BFS 起点为顶点 1
    while(!que.empty()){ // BFS,求 1 到每个点的奇偶最短路
        int cura=que.front().first;
        int bu=que.front().second;
        que.pop();
        for(int i=0;i<a[cura].size();i++){
            if(bu%2==0){
                if(ji[a[cura][i]]>bu+1){
                    ji[a[cura][i]]=bu+1;
                    que.push(make_pair(a[cura][i],bu+1));
                }
            }
            else{
                if(ou[a[cura][i]]>bu+1){
                    ou[a[cura][i]]=bu+1;
                    que.push(make_pair(a[cura][i],bu+1));
                }
            }
        }
    }
    // 按照所走步数奇偶判断可否到达
    int cura,l;
    while(q--){
        scanf("%d%d",&cura,&l);
        if(l%2==0){
            if(ou[cura]<=l) printf("Yes\n");
            else printf("No\n");
        }
        else{
            if(ji[cura]<=l) printf("Yes\n");
            else printf("No\n");
        }
    }
    return 0;
}
posted @ 2026-07-31 23:14  tz_zhao  阅读(29)  评论(0)    收藏  举报