HDU3656-Fire station

来源:互联网 发布:湖北地税网络纳税 编辑:程序博客网 时间:2024/05/22 02:17

Fire station

                                                                  Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
                                                                                            Total Submission(s): 1733    Accepted Submission(s): 585


Problem Description
A city's map can be seen as a two dimensional plane. There are N houses in the city and these houses can be seen as N points P1 …… PN on the two dimensional plane. For simplicity's sake, assume that the time spent from one house number to another is equal to the distance between two points corresponding to the house numbers. The government decides to build M fire stations from N houses. (If a station is build in Pi, We can think the station is next to the house and the time from the station to the house is considered zero.) It is obvious that if some place such as Pi is breaking out of fire, the nearest station will dispatched a fire engine quickly rushed to the rescue scene. The time it takes from this station to the rescue scene is called rescue time. Now you need to consider about a problem that how to choice the positions of the M fire station to minimize the max rescue time of all the houses.
 

Input
The fi rst line of the input contains one integer T, where T is the number of cases. For each case, the fi rst line of each case contains two integers N and M separated by spaces (1 ≤ M ≤N ≤ 50), where N is the number of houses and M is the number of fire stations. Then N lines is following. The ith line contains two integers Xi and Yi (0 ≤ Xi, Yi ≤ 10000), which stands for the coordinate of the ith house.
 

Output
The rescue time which makes the max rescue time is minimum.
 

Sample Input
24 21 11 22 32 44 11 11 22 32 4
 

Sample Output
1.0000002.236068
 

Author
wwr & fengzlzl
 

Source
2010 Asia Regional Chengdu Site —— Online Contest
 


题意:有n个城市在二维平面上,要选一些城市建消防站,不超过m个,消防站要把所有城市覆盖住,那么覆盖半径最小为多少。如果某个城市有消防站,那么这个城市和消防站的距离为0

解题思路:二分+舞蹈链,每次二分到一个距离,判断每个城市建消防站可以覆盖哪些城市,然后用舞蹈链的重复覆盖判断出最少需要几个城市


#include <iostream>    #include <cstdio>    #include <cstring>    #include <string>    #include <algorithm>    #include <cctype>    #include <map>    #include <cmath>    #include <set>    #include <stack>    #include <queue>    #include <vector>    #include <bitset>    #include <functional>    using namespace std;#define LL long long    const int INF = 0x3f3f3f3f;const int maxn = 500005;int n, m, x[55], y[55], tot;double dis[3000];struct DLX{int L[maxn], R[maxn], U[maxn], D[maxn];int row[maxn], col[maxn], sum[maxn], ans[maxn];int n, m, cnt, num;int vis[maxn];void add(int k, int l, int r, int u, int d, int x, int y){L[k] = l;   R[k] = r;   U[k] = u;D[k] = d;   row[k] = x;  col[k] = y;}void reset(int n, int m){num = 0x7FFFFFFF;this->n = n;   this->m = m;for (int i = 0; i <= m; i++){add(i, i - 1, i + 1, i, i, 0, i);sum[i] = 0;}L[0] = m, R[m] = 0, cnt = m + 1;}void insert(int x, int y){int temp = cnt - 1;if (row[temp] != x){add(cnt, cnt, cnt, U[y], y, x, y);U[D[cnt]] = cnt; D[U[cnt]] = cnt;}else{add(cnt, temp, R[temp], U[y], y, x, y);R[L[cnt]] = cnt; L[R[cnt]] = cnt;U[D[cnt]] = cnt; D[U[cnt]] = cnt;}sum[y]++, cnt++;}void Remove(int k){for (int i = D[k]; i != k; i = D[i]){L[R[i]] = L[i];R[L[i]] = R[i];}}void Resume(int k){for (int i = U[k]; i != k; i = U[i]) L[R[i]] = R[L[i]] = i;}int A(){int dis = 0;for (int i = R[0]; i != 0; i = R[i]) vis[i] = 0;for (int i = R[0]; i != 0; i = R[i])if (!vis[i]){dis++, vis[i] = 1;for (int j = D[i]; j != i; j = D[j])for (int k = R[j]; k != j; k = R[k])vis[col[k]] = 1;}return dis;}void Dfs(int k){if (!R[0]) { num = min(num, k); return ; }else if (k + A() < num){int now = R[0];for (int i = R[0]; i != 0; i = R[i])if (sum[now] > sum[i]) now = i;for (int i = D[now]; i != now; i = D[i]){Remove(i);for (int j = R[i]; j != i; j = R[j]) Remove(j);Dfs(k + 1);for (int j = L[i]; j != i; j = L[j]) Resume(j);Resume(i);}}}}dlx;int main(){int t;scanf("%d", &t);while (t--){scanf("%d%d", &n, &m);tot = 0;dis[tot++] = 0;for (int i = 1; i <= n; i++){scanf("%d%d", &x[i], &y[i]);for (int j = 1; j < i; j++)dis[tot++] = sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j])*(y[i] - y[j]));}sort(dis, dis + tot);tot = unique(dis, dis + tot) - dis;int l = 0, r = tot - 1, ans;while (l <= r){int mid = (l + r) >> 1;dlx.reset(n, n);for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++){double temp = sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j])*(y[i] - y[j]));if (dis[mid] >= temp) dlx.insert(i, j);}dlx.Dfs(0);if (dlx.num <= m) r = mid - 1, ans = mid;else l = mid + 1;}printf("%.6lf\n", dis[ans]);}return 0;}