P5663 [CSP-J2019] 加工零件

(文章目录)


前言

其实我感觉本题的难点在于分成奇偶两个不同的最短路来计算,图论和最短路其实不难想。


题目大意

题面有点长,还是放一下链接吧。题目传送门


思路

首先看到这题,图论肯定能想到。之后就可以想出一个暴力做法,模拟一遍这个过程,做一次dfs,然后判断。光看到 LL 的范围就知道肯定不对。之后想了想,这个 LL 的范围肯定没有什么在线处理 logn\log{n} 的算法了,极大可能要做预处理然后 O(1)\mathcal{O}(1) 回答。

之后让我们转化一下思路,其实就是问在 aa11 之间存不存在一条长度为 LL 的路径。考虑最短路,如果从 aa11 的最短路比 LL 大,那么肯定LL 开始不需要到。但是可能出现来回来回的情况。

之后再次进行考虑,可以发现,在两条边之间来回走就可以自给自足了,每一次来回增加 11 的阶段需要走两次,也就是如果这条边的最短路走出来了 33,那么也一定可以走出 5,75,7\cdots但是不可以确定能否走出 66,但是偶数如果走出来 22 就一定可以走出 66,所以要按照奇偶分最短路。之后在根据 LL 的奇偶对奇偶最短路进行判断即可。

需要注意,如果 11 是孤立的,则它没有偶数最短路,所以做bfs时先把 11 的连接边放进队列里即可。


代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const ll MAXN=1e5+5;
vector<ll>adj[MAXN];
ll dis[MAXN][3];
ll n,m,Q;
int main(){
    scanf("%lld%lld%lld",&n,&m,&Q);
    for (int i = 1; i <=m ; ++i) {
        ll u,v;
        scanf("%lld%lld",&u,&v);
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    memset(dis,0x3f,sizeof(dis));
    queue<pair<ll,ll> >q;
    for (int i = 0; i <adj[1].size() ; ++i) {
        ll v=adj[1][i];
        dis[v][1]=1;
        q.push({v,1});
    }
    while (!q.empty()){
        ll u=q.front().first,w=q.front().second+1;
        q.pop();
        for (int i = 0; i <adj[u].size() ; ++i) {
            ll v=adj[u][i],type=w%2;
            if(w<dis[v][type]){
                dis[v][type]=w;
                q.push({v,w});
            }
        }
    }
    for (int T = 1; T <=Q ; ++T) {
        ll a,L;
        scanf("%lld%lld",&a,&L);
        if(dis[a][L%2]>L){
            printf("No\n");
        }else{
            printf("Yes\n");
        }
    }
    return 0;
}


总结

我们知道了本题可以使用奇偶最短路进行判断,同时可以根据暴力和输入数据的大小去推断可能的算法。在本题中我们通过暴力和 LL 的范围推断出不太可能有在线的做法。