3832.Earth Hour
标签:图论,最短路
题意:给定n个路灯的坐标和照射半径,当两个路灯的照射范围相交时,这两个路灯视为相连,现在问在保证前三个路灯相连的情况下,最多可以关闭多少路灯,若无法相连,则输出-1
题解
题目要求尽可能多地关闭路灯,实际上也就是要求尽可能少地打开路灯使得前三个路灯相连,如果前三个路灯相连,那么肯定存在一个中转路灯能连接这三个路灯,而相连我们可以用连边来表示,所以问题可以转化为前三个路灯到这个中转路灯的最短距离,这个最短距离我们可以分别以前三个路灯为源点,用spfa或dij求单源最短路径,最后遍历这个中转路灯,三个最短距离的和 + 1的最小值就是最少需要打开的路灯,那么答案用n减去这个结果即可
需要注意的是,如果你没有开longlong,在对距离数组赋初值的时候,不能赋值成接近1e9这么大的数(虽然平常习惯如此),这是因为本题中会出现三个距离数组相加的情况,这样某些情况加起来会爆int
代码实现
spfa
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <math.h>
#define ll long long
using namespace std;
int t, n;
struct node{
int x, y, r;
}e[1010];
int d[1010][1010], dis[4][1010], vis[1010];
void spfa(int s){
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++) dis[s][i] = 1e6;
dis[s][s] = 0;
vis[s] = 1;
queue<int> q;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
vis[u] = 0;
for(int i = 1; i <= n; i++){
if(dis[s][u] + d[u][i] < dis[s][i]){
dis[s][i] = dis[s][u] + d[u][i];
if(!vis[i]){
vis[i] = 1;
q.push(i);
}
}
}
}
}
int main(){
cin >> t;
while(t--){
cin >> n;
for(int i = 1; i <= n; i++) cin >> e[i].x >> e[i].y >> e[i].r;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
double tmp = sqrt((double)(e[i].x - e[j].x) * (e[i].x - e[j].x) + (e[i].y - e[j].y) * (e[i].y - e[j].y));
if(tmp <= e[i].r + e[j].r) d[i][j] = 1;
else d[i][j] = 1e6;
d[i][i] = 0;
}
}
spfa(1);
spfa(2);
spfa(3);
int ans = 1e6, f = 0;
if(dis[1][2] == 1e6 || dis[1][3] == 1e6 || dis[2][3] == 1e6) f = 1;
if(f) cout << -1 << "\n";
else{
for(int i = 1; i <= n; i++) ans = min(ans, dis[1][i] + dis[2][i] + dis[3][i]);
cout << n - ans - 1 << "\n";
}
}
return 0;
}
dij
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <math.h>
#define ll long long
using namespace std;
const int N = 40050;
int t, n, cnt;
int now[N];
struct node{
int x, y, r;
}e[210];
struct Node{
int u, w;
};
bool operator <(Node x, Node y){
return x.w > y.w;
}
struct nn{
int u, v, w;
}ee[N];
int dis[4][210], vis[210];
void add(int u, int v, int w){
ee[++cnt].u = now[u];
now[u] = cnt;
ee[cnt].v = v;
ee[cnt].w = w;
}
void dij(int s){
priority_queue<Node> q;
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++) dis[s][i] = 1e6;
dis[s][s] = 0;
q.push(Node{s, 0});
while(!q.empty()){
Node tmp = q.top();
q.pop();
int u = tmp.u;
if(vis[u]) continue;
vis[u] = 1;
for(int i = now[u]; i; i = ee[i].u){
int v = ee[i].v;
if(dis[s][u] + ee[i].w < dis[s][v]){
dis[s][v] = dis[s][u] + ee[i].w;
q.push(Node{v, dis[s][v]});
}
}
}
}
int main(){
cin >> t;
while(t--){
memset(now, 0, sizeof(now));
memset(ee, 0, sizeof(ee));
cnt = 0;
cin >> n;
for(int i = 1; i <= n; i++) cin >> e[i].x >> e[i].y >> e[i].r;
for(int i = 1; i <= n; i++){
add(i, i, 0);
for(int j = i + 1; j <= n; j++){
double tmp = sqrt((double)(e[i].x - e[j].x) * (e[i].x - e[j].x) + (e[i].y - e[j].y) * (e[i].y - e[j].y));
if(tmp <= e[i].r + e[j].r) add(i, j, 1), add(j, i, 1);
else add(i, j, 1e6), add(j, i, 1e6);
}
}
dij(1);
dij(2);
dij(3);
int ans = 1e6;
int f = 0;
if(dis[1][2] == 1e6 || dis[1][3] == 1e6 || dis[2][3] == 1e6) f = 1;
if(f) cout << -1 << "\n";
else{
for(int i = 1; i <= n; i++) ans = min(ans, dis[1][i] + dis[2][i] + dis[3][i]);
cout << n - ans - 1 << "\n";
}
}
return 0;
}