Official

C - Virus Editorial by cn449


\(1,2, \ldots, N\)\(N\) 頂点からなるグラフにおいて、\((X_i,Y_i)\)\((X_j,Y_j)\) の距離が \(D\) 以下であるとき、またそのときに限り頂点 \(i\) と頂点 \(j\) を結ぶ無向辺が存在するとします。

\(i\) がウイルスに感染する必要十分条件は、上で定めたグラフにおいて頂点 \(1\) と頂点 \(i\) を結ぶパスが存在する、すなわち頂点 \(1\) と頂点 \(i\) が同じ連結成分に属することです。

したがって、DFS や BFS, Union-Find などのグラフ上の探索アルゴリズムを用いて正答を得ることができます。

DFS や BFS を用いるとグラフの頂点数は \(N\)、辺の数は \(O(N^2)\) であるため時間計算量は \(O(N^2)\)であり、Union-Find を用いるとオーダーの面では少し悪化しますが十分高速です。(追記:オーダーが悪化するというのは筆者の勘違いで、実際には適切な実装のもと最悪計算量のオーダーは悪化しないようです。詳しくはこちらのユーザ解説を参照ください。)

実装例

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

int main() {
	int n, d;
	cin >> n >> d;
	vector<int> x(n), y(n);
	for (int i = 0; i < n; i++) cin >> x[i] >> y[i];
	vector<vector<bool>> graph(n, vector<bool>(n));
	for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) if ((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]) <= d * d) graph[i][j] = true;
	vector<bool> ans(n);
	ans[0] = true;
	queue<int> que; que.push(0);
	while (!que.empty()) {
		int q = que.front(); que.pop();
		for (int i = 0; i < n; i++) {
			if (graph[q][i] && !ans[i]) {
				ans[i] = true;
				que.push(i);
			}
		}
	}
	for (int i = 0; i < n; i++) cout << (ans[i] ? "Yes" : "No") << '\n';
}

posted:
last update: