Dijkstra 求“传递闭包”
第一篇题解,Dijkstra求连通性
看了下数据范围
0x0 虚拟结点(dummy node)
显然,上下两个平面都可以视为一个虚拟结点,对于这两个虚拟节点
所以我们共有
0x1 建图&&\mathcal{Dijkstra}
那么我们判断
那,仿照Dijkstra 算法,我们只需要修改转移函数即可。
d[i][j] := 代表是否存在连接,1为yes, 0为nog[i] := 代表从开始结点 s 到各个结点的连通关系- 转移式为
g[y] |= (g[x] & d[x][y])
这样之后就可以直接跑 Dijkstra 快到起飞!
#include <bits/stdc++.h>
#define vt std::vector
#define int long long
constexpr int inf = 0x3f3f3f3f;
int d[1005][1005]; // 代表两点之间的关系
int g[1005]; // 代表从开始结点 s 出发到其他点的关系
// 用 tup 代替结构体
using tup = std::tuple<long long, long long, long long>;
int n, h, r;
void dijkstra(int s){
for (int i = 0; i <= n + 1; ++ i) g[i] = (i == 0 ? 1 : 0);
vt<int> vis(n + 2, 0);
for (int i = 0; i < n + 2; ++ i){
int x;
for (int y = 0; y <= n + 1; ++ y) if (!vis[y] && g[y]) x = y;
vis[x] = 1;
for (int y = 0; y <= n + 1; ++ y) g[y] |= (g[x] & d[x][y]); // 关键一步
}
}
void solve(){
std::cin >> n >> h >> r;
vt<tup> points;
for (int i = 0; i < n; ++ i){
int x, y, z;
std::cin >> x >> y >> z;
points.push_back(std::make_tuple(x, y, z));
}
auto calc = [&](tup &a, tup &b){
int dis =
(std::get<0>(a) - std::get<0>(b)) * (std::get<0>(a) - std::get<0>(b)) +
(std::get<1>(a) - std::get<1>(b)) * (std::get<1>(a) - std::get<1>(b)) +
(std::get<2>(a) - std::get<2>(b)) * (std::get<2>(a) - std::get<2>(b));
if (dis <= (4 * r * r)) return 1;
return 0;
};
int s = 0, t = n + 1;
memset(d, 0, sizeof(d));
for (int i = 1; i <= n; ++ i){
for (int j = i; j <= n; ++ j){
if (i == j) d[i][j] = 0;
d[i][j] = d[j][i] = calc(points[i - 1], points[j - 1]);
}
if (std::get<2>(points[i - 1]) <= r) d[0][i] = d[i][0] = 1;
if (h - std::get<2>(points[i - 1]) <= r) d[i][n + 1] = d[n + 1][i] = 1;
}
dijkstra(s);
std::cout << (g[t] ? "Yes" : "No") << "\n";
}
signed main(){
std::ios::sync_with_stdio(0), std::cin.tie(0);
int t;
std::cin >> t;
while (t--) solve();
return 0;
}