通讯延迟(csp第35次)
时间限制: 1.5 秒
空间限制: 512 MiB
相关文件: 题目目录(样例文件)
题目描述
给定二维平面上 n 个节点,以及 m 个通讯基站。第 i 个基站可以覆盖以坐标 (xi,yi) 为中心、2ri 为边长的正方形区域,并使正方形区域内(包含边界)所有节点以 ti 单位时间的延迟进行相互通讯。
求节点 1 到 n 的最短通讯延迟。
输入格式
从标准输入读入数据。
第一行包含空格分隔的两个正整数 n、m;
接下来 n 行,每行两个整数 xi,yi,代表第 i 个节点的坐标;
接下来 m 行,每行四个整数 xj,yj,rj,tj,代表第 j 个通讯基站的坐标,通讯半径与通讯延迟。
输出格式
输出到标准输出。
输出一行,即节点 1 到 n 的最短通讯延迟;如果无法通讯,则输出 Nan
。
样例输入
1 2 3 4 5 6 7 8 9 10 11
| 5 5 0 0 2 4 4 0 5 3 5 5 1 2 2 5 3 5 2 6 2 0 2 1 4 2 2 3 5 4 1 2
|
样例输出
样例解释
1 号通讯基站延迟为 5,覆盖节点 1、2;
2 号通讯基站延迟为 6,覆盖节点 2、4、5;
3 号通讯基站延迟为 1,覆盖节点 1、3;
4 号通讯基站延迟为 3,覆盖节点 2、3、4;
5 号通讯基站延迟为 2,覆盖节点 4、5。
最短延迟方案为:
节点 1 通过 3 号基站传讯至节点 3,延迟 1;
节点 3 通过 4 号基站传讯至节点 4,延迟 3;
节点 4 通过 5 号基站传讯至节点 5,延迟 2;
总计延迟为 6。
子任务
30 的测试数据满足 n,m≤100;
对于额外 30 的测试数据,每个通讯基站至多覆盖 20 个节点;
全部的测试数据满足 n,m≤5000 且 0≤xi,yi,ri≤10^9、1≤ti≤10^5。
题解
- 初看此题容易想到dijkstra
- 但本题的难点在于建图 同一个基站内的点两两建边 所费时间代价不小 且建出来的图将会十分复杂
- 本题所给数据下 稀疏图与稠密图的极端情况均有可能出现 dijkstra堆优化之后最短路算法本身已经没有多少优化的余地
- 点的范围很大 实际涉及点数不那么多 想到离散化 但其对图的复杂度于事无补
- 于是看到了这个惊为天人的想法:虚拟节点!
- 对于一个站覆盖的范围 新建一个虚拟节点 再建所有节点通向虚拟节点的边 与虚拟节点通向所有节点的边 (它们的边权之和为t) 自然实现了这些点两两之间的双向连接 且边的条数从k(k-1)减为2k 大大简化了图 之后便可没有后顾之忧的使用堆优化版的dijkstra啦!
代码与注释
notice!数组要开的足够大 以防RE……
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
#include <bits/stdc++.h> using namespace std; const int N = 200100 * 2;
typedef pair<int, int> PII; int h[N], w[N*20], e[N*20], ne[N*20], idx; int dist[N]; bool st[N];
void add(int a, int b, int c) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; } int dijkstra(int n) { memset(dist, 0x3f, sizeof dist); dist[1] = 0; priority_queue<PII, vector<PII>, greater<PII>> q; q.push({0, 1}); while (q.empty() == 0) { int d = q.top().first, u = q.top().second; q.pop(); if(st[u]) continue; st[u] = 1; for(int l = h[u]; l!=-1; l=ne[l]) { int td = w[l], v = e[l]; if(st[v]) continue; if(d+td < dist[v]) { dist[v] = d+td; q.push({dist[v], v}); } } } if(dist[n]==0x3f3f3f3f) return -1; else return dist[n]; } int main() { int n, m; scanf("%d%d", &n, &m); PII node[N]; for(int i=1; i<=n; i++) { scanf("%d%d", &node[i].first, &node[i].second); } memset(h, -1, sizeof h); idx = 0; for(int i=1; i<=m; i++) { int x, y, r, t; scanf("%d%d%d%d", &x, &y, &r, &t); int lx = x-r, rx = x+r, ly = y-r, ry = y+r; int vi = n+i; for(int j=1; j<=n; j++) { if(node[j].first>=lx&&node[j].first<=rx&&node[j].second>=ly&&node[j].second<=ry) { add(j, vi, 0); add(vi, j, t); } } } int res = dijkstra(n); if(res == -1) puts("Nan"); else printf("%d\n", res); return 0; }
|