本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1558. 加油站
原题传送:AcWing 1558. 加油站
加油站的建造位置必须使加油站与距离它最近的房屋的距离尽可能远。
与此同时,它还必须保证所有房屋都在其服务范围内。
现在,给出了城市地图和加油站的几个候选位置,请你提供最佳建议。
如果有多个解决方案,请输出选取位置与所有房屋的平均距离最小的解决方案。
如果这样的解决方案仍然不是唯一的,请输出选取位置编号最小的解决方案。
输入格式
第一行包含四个整数 ,房屋总数, ,加油站的候选位置总数, ,连接房屋或加油站的道路总数, 加油站的最大服务范围。
所有房屋的编号从 到 ,所有加油站侯选位置编号从 G1 到 GM。
接下来 行,每行格式如下:
P1 P2 Dist
其中,P1 和 P2 表示一条无向道路连接的两个房屋或加油站侯选位置的编号,Dist 是道路长度,这是一个整数。
输出格式
第一行输出所选位置的编号。
第二行输出加油站与距离其最近的房屋之间的距离以及与所有房屋之间的平均距离,精确到小数后一位。
如果解决方案不存在,则输出 No Solution。
数据范围
, , , ,
输入样例1:
4 3 11 5
1 2 2
1 4 2
1 G1 4
1 G2 3
2 3 2
2 G2 1
3 4 2
3 G3 2
4 G1 3
G2 G1 1
G3 G2 2
输出样例1:
G1
2.0 3.3
输入样例2:
2 1 2 10
1 G1 9
2 G1 20
输出样例2:
No Solution
思路:
dijkstra求每个加油站到所有房屋的距离,求距离最近的房屋尽可能远的加油站,如果相等,选取总距离最小的加油站。
题解:
#include<bits/stdc++.h>
using namespace std;
const int N = 1020, INF = 0x3f3f3f3f;
int n, m, k, D;
int g[N][N];
int dist[N];
bool st[N];
int get(string s)
{
if(s[0] == 'G') return n + stoi(s.substr(1));
return stoi(s);
}
void dijkstra(int start, int &mind, int &sumd)
{
memset(dist, 0x3f, sizeof dist);
memset(st, 0, sizeof st);
dist[start] = 0;
for(int i = 0; i < n + m; i++)
{
int t = -1;
for(int j = 1; j <= n + m; j++)
if(!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
st[t] = true;
for(int j = 1; j <= n + m; j++)
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
for(int i = 1; i <= n; i++)
{
if(dist[i] > D)
{
mind = -INF;
return;
}
}
mind = INF, sumd = 0;
for(int i = 1; i <= n; i++)
{
mind = min(mind, dist[i]);
sumd += dist[i];
}
}
int main()
{
cin >> n >> m >> k >> D;
memset(g, 0x3f, sizeof g);
while(k--)
{
string a, b;
int z;
cin >> a >> b >> z;
int x = get(a), y = get(b);
g[x][y] = g[y][x] = min(g[x][y], z);
}
int res = -1, mind = 0, sumd = INF;
for(int i = n + 1; i <= n + m; i++)
{
int d1, d2;
dijkstra(i, d1, d2);
if(d1 > mind) res = i, mind = d1, sumd = d2;
else if(d1 == mind && d2 < sumd) res = i, sumd = d2;
}
if(res == -1)
printf("No Solution\n");
else
printf("G%d\n%.1lf %.1lf\n", res - n, (double)mind, (double)sumd / n + 1e-8);
return 0;
}