[CSP-J2 2019]加工零件 题解

[CSP-J2 2019]加工零件 题解

题目地址:洛谷:P5663 加工零件 – 洛谷 | 计算机科学教育新生态

题目描述

凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇。工厂里有 $n$ 位工人,工人们从 $1 \sim n$ 编号。某些工人之间存在双向的零件传送带。保证每两名工人之间最多只存在一条传送带。

如果 $x$ 号工人想生产一个被加工到第 $L \ (L \gt 1)$ 阶段的零件,则所有与 $x$ 号工人有传送带直接相连的工人,都需要生产一个被加工到第 $L – 1$ 阶段的零件(但 $x$ 号工人自己无需生产第 $L – 1$ 阶段的零件)。

如果 $x$ 号工人想生产一个被加工到第 $1$ 阶段的零件,则所有与 $x$ 号工人有传送带直接相连的工人,都需要为 $x$ 号工人提供一个原材料。

轩轩是 $1$ 号工人。现在给出 $q$ 张工单,第 $i$ 张工单表示编号为 $a_i$​ 的工人想生产一个第 $L_i$​ 阶段的零件。轩轩想知道对于每张工单,他是否需要给别人提供原材料。他知道聪明的你一定可以帮他计算出来!

题意简述

给定一个 $n$ 个点 $m$ 条边的无向图,如果给 $x$ 号点标注 $L$ ,则与 $x$ 点相邻的点都会被标注 $L-1$ ,以此类推。有 $q$ 个询问,每个询问问给 $a$ 点标注 $L$ , $1$ 点是否会被标注 $0$ 。

输入输出格式

输入格式:

第一行三个正整数 $n$,$m$ 和 $q$,分别表示工人的数目、传送带的数目和工单的数目。

接下来 $m$ 行,每行两个正整数 $u$ 和 $v$,表示编号为 $u$ 和 $v$ 的工人之间存在一条零件传输带。保证 $u \neq v$。

接下来 $q$ 行,每行两个正整数 $a$ 和 $L$,表示编号为 $a$ 的工人想生产一个第 $L$ 阶段的零件。

输出格式:

共 $q$ 行,每行一个字符串 Yes 或者 No。如果按照第 $i$ 张工单生产,需要编号为 $1$ 的轩轩提供原材料,则在第 $i$ 行输出 Yes;否则在第 $i$ 行输出 No。注意输出不含引号。

输入输出样例

样例 #1

输入样例 #1:

3 2 6
1 2
2 3
1 1
2 1
3 1
1 2
2 2
3 2

输出样例 #1:

No
Yes
No
Yes
No
Yes

样例 #2

输入样例 #2:

5 5 5
1 2
2 3
3 4
4 5
1 5
1 1
1 2
1 3
1 4
1 5

输出样例 #2:

No
Yes
No
Yes
Yes

数据范围

共 20 个测试点。

$1 \leq u, v, a \leq n$。

测试点 $1 \sim 4$ ,$1 \leq n, m \leq 1000$,$q = 3$,$L = 1$。

测试点 $5 \sim 8$,$1 \leq n, m \leq 1000$,$q = 3$,$1 \leq L \leq 10$。

测试点 $9 \sim 12$,$1 \leq n, m, L \leq 1000$,$1 \leq q \leq 100$。

测试点 $13 \sim 16$,$1 \leq n, m, L \leq 1000$,$1 \leq q \leq 10^5$。

测试点 $17 \sim 20$,$1 \leq n, m, q \leq 10^5$,$1 \leq L \leq 10^9$。

题解

容易发现,需要提供原材料的点到询问点一定存在长度为 $L$ 的路径,这里的路径可以存在重复经过边的情况。则问题转化为:$1$ 点到 $a$ 点是否存在长度为 $L$ 的路径。

由于沿着一条边走一个来回会让一条路径变长 $2$ ,如果 $1$ 到 $a$ 存在长为 $d$ 的路径,那么也就存在长为 $d + 2k \ (k \in \mathbb{N})$ 的路径。如果 $1$ 到 $a$ 长度为奇数的最短路径长为 $d_{\text{odd}}$ ,则不小于 $d_{\text{odd}}$ 的奇数长度的路径都存在,偶数以此类推。

因此,我们只需要求出 $1$ 到其他点的长为奇数/偶数的最短路径长度即可回答每个询问,如果 $L$ 是奇数且不小于 $1$ 到 $a$ 的奇数长度最短路径,则可行,偶数以此类推。

处理奇数/偶数长度最短路可以用一个 BFS 来做。从 $1$ 开始进行 BFS ,每次用队列中一个点的当前奇数/偶数长度最短路更新相邻点的偶数/奇数最短路即可。由于边长都为 $1$ ,每个点最多只会加入队列 $2$ 次,因此 BFS 的复杂度为 $O(n)$ ,单次回答复杂度为 $O(1)$ ,因此处理询问复杂度为 $O(q)$ ,总复杂度为 $O(n)$ 。

洛谷民间数据中,有一个点的 $1$ 点没有连边,因此所有的答案都为 No ,需要特判。

代码

// Code by KSkun, 2019/11
#include <cstdio>
#include <cctype>
#include <cstring>

#include <algorithm>
#include <utility>
#include <vector>
#include <queue>

typedef long long LL;
typedef std::pair<int, int> PII;

inline char fgc() {
	static char buf[100000], * p1 = buf, * p2 = buf;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
		? EOF : *p1++;
}

inline LL readint() {
	LL res = 0, neg = 1; char c = fgc();
	for(; !isdigit(c); c = fgc()) if(c == '-') neg = -1;
	for(; isdigit(c); c = fgc()) res = res * 10 + c - '0';
	return res * neg;
}

inline char readsingle() {
	char c;
	while(!isgraph(c = fgc())) {}
	return c;
}

const int MAXN = 100005,
		INF = 0x3f3f3f3f;

int n, m, q, deg[MAXN], dise[MAXN], diso[MAXN];
bool inque[MAXN];
std::vector<int> gra[MAXN];

void bfs(int st) {
	std::queue<int> q;
	memset(dise, 0x3f, sizeof(dise));
	memset(diso, 0x3f, sizeof(diso));
	dise[st] = 0; 
	q.push(st); inque[st] = true;
	while (!q.empty()) {
		int u = q.front(); q.pop(); inque[u] = false;
		for (int v : gra[u]) {
			bool suc = false;
			if (dise[u] + 1 < diso[v]) {
				diso[v] = dise[u] + 1;
				suc = true;
			}
			if (diso[u] + 1 < dise[v]) {
				dise[v] = diso[u] + 1;
				suc = true;
			}
			if (suc && !inque[v]) {
				q.push(v); inque[v] = true;
			}
		}
	}
}

int main() {
	n = readint(); m = readint(); q = readint();
	for (int i = 1, u, v; i <= m; i++) {
		u = readint(); v = readint();
		gra[u].push_back(v);
		gra[v].push_back(u);
		deg[u]++; deg[v]++;
	}
	bfs(1);
	while (q--) {
		int a = readint(), L = readint();
		if (deg[1] == 0) puts("No");
		else if (L % 2 == 0 && L >= dise[a]) puts("Yes");
		else if (L % 2 == 1 && L >= diso[a]) puts("Yes");
		else puts("No");
	}
	return 0;
}


发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据