传送门
// 题意 : 给定n(n>=3)个路灯的二维平面上的位置以及他们能照射到的范围r, 如果两个路灯照射的范围有重合的地方, 那么说明这两个路灯是相连的. 问现在最多可以关闭多少个路灯使得前三个路灯是联通的, 如果怎么都不能使前三个路灯相连就输出-1.
// 思路: 那么我们首先n^2建图, 通过照射的范围来, 然后我们就把问题转化为在图中如何删去尽量多的点使得三个固定点依然联通, 我们就可以发现一定存在着某个点它连接着三个点, 并且路径没有重合的部分(这个点可以是前三个点的某一个点), 所以我们跑最短路, 求出前三个点到图中任意一个点的最短距离, 设任意两点之间的距离为1, 然后O(n)的枚举出那个点即可出答案.
注: 虽然n很小, 但是有case, 所以不要用floyd来跑最短路,会T的(试过了~), 由于边长都为1, 所以直接bfs就行, bfs三次即可求出前三个点到所有点的最短距离了.O(n)的复杂度求最短距离, 一定能过了.
AC Code
const int maxn = 2e2+5;
struct node {
db x, y, r;
}e[maxn];
int n;
vector<int>g[maxn];
bool check(node a, node b) {
db dis = sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
if (dis<=a.r+b.r) return true;
return false;
}
int dis[5][maxn];
bool vis[maxn];
void bfs(int st) {
Fill(dis[st], inf);
dis[st][st] = 0;
queue<int>q; Fill(vis, 0);
q.push(st); vis[st] = 1;
while(!q.empty()) {
int u = q.front();
q.pop();
for (auto i : g[u]) {
if (vis[i]) continue;
dis[st][i] = dis[st][u] + 1;
vis[i] = 1;
q.push(i);
}
}
}
void solve()
{
scanf("%d",&n);
for (int i = 1 ; i <= n ;i ++) {
scanf("%lf%lf%lf", &e[i].x, &e[i].y, &e[i].r);
}
for (int i = 1 ; i <= n ; i ++) g[i].clear();
for (int i = 1 ; i <= n ; i ++) {
for (int j = 1 ; j <= n ; j ++) {
if (i != j && check(e[i], e[j])) {
g[i].pb(j); g[j].pb(i);
}
}
}
bfs(1); bfs(2); bfs(3);
ll ans = inf;
for (int i = 1 ; i<= n ; i ++) {
ans = min(ans, 1ll*dis[1][i] + 1ll*dis[2][i] + 1ll*dis[3][i]);
}
if (ans == inf) printf("-1\n");
else printf("%d\n", n - ans - 1);
}