noip模拟赛 radius
分析:这道题实在是不好想,一个可以骗分的想法是假定要求的那个点在中心点上,可以骗得不少分.但是在边上的点要怎么确定呢?理论复杂度O(﹢无穷).答案一定是和端点有关的,涉及到最大值最小,考虑二分最大值,关键就是怎么check.如果有一条边x,还有一个点y,把y到x上的点的距离>mid的点给标记上,这样就会形成许多个区间,判断一下x是否被这些区间给完全覆盖住了,如果没有被完全覆盖住,证明这个最大值可以更小.思路非常奇妙,具体实现细节可以参看代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 210, maxm = 40010; int n, m, a[maxn][maxn], head[maxn], to[maxm],ans,len,top,nextt[maxm],w[maxm], tot = 1; struct node { int x, y, z; }e[20000]; struct node2 { int first, second; }e2[20000]; void add(int x, int y, int z) { w[tot] = z; to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } void floyd() { for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (a[i][j] > a[i][k] + a[k][j]) a[i][j] = a[i][k] + a[k][j]; } void add2(int x, int y) { e2[++top].first = x; e2[top].second = y; } bool cmp(node2 a, node2 b) { if (a.first == b.first) return a.second < b.second; return a.first < b.first; } bool can() { int x = 0; sort(e2 + 1, e2 + 1 + top,cmp); for (int i = 1; i <= top; i++) { if (x < e2[i].first) return false; if (x > e2[i].second) continue; x = e2[i].second + 1; } if (x > len) return true; return false; } bool check(int p) { bool flag = false; for (int i = 1; i <= m; i++) { top = 0; len = e[i].z; for (int j = 1; j <= n; j++) { int x = p - a[e[i].x][j]; int y = p - a[e[i].y][j]; if (x < 0 && y < 0) { add2(0, e[i].z); break; } if (x >= e[i].z || y >= e[i].z) continue; if (x + y >= e[i].z) continue; add2(max(0, x + 1), min(e[i].z, e[i].z - y - 1)); } if (!can()) flag = 1; if (flag) break; } if (flag) return true; return false; } int main() { memset(a, 127 / 3, sizeof(a)); scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { int u, v, z; scanf("%d%d%d", &u, &v, &z); z *= 2; add(u, v, z); add(v, u, z); e[i].x = u; e[i].y = v; e[i].z = z; a[u][v] = a[v][u] = min(a[u][v], z); } for (int i = 1; i <= n; i++) a[i][i] = 0; floyd(); int l = 0, r = 10000010; while (l <= r) { int mid = (l + r) >> 1; if (check(mid)) { ans = mid; r = mid - 1; } else l = mid + 1; } double temp = ans / 2.0; printf("%.2lf\n", temp); return 0; }