您的位置:首页 > 其它

hdu 3656 Fire station 重复覆盖 DLX+二分答案 给出一些城市及一些救火站的坐标,要求这些救火站覆盖所有的城市,问从救火站到城市的最长时间至少是多少。

2011-09-16 18:02 465 查看
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

2
4 2
1 1
1 2
2 3
2 4
4 1
1 1
1 2
2 3
2 4


Sample Output

1.000000
2.236068


//

#include<stdio.h>

#include<math.h>

#include<string.h>

#include<algorithm>

#include<iostream>

using namespace std;

#define eps 1e-8

#define N 85

#define V 36000

int n,m,K;//n行 m列 K限制条件,最多用K行(仅限于此题)

int L[V],R[V];

int D[V],U[V];

int C[V];

int S
,H
;

int ak,size;//ak 最少多少行可以覆盖所有列(可重复)

double dis(double x1,double y1,double x2,double y2)

{

return sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));

}

void Link(int r,int c)

{

S[c]++;C[size]=c;

U[size]=U[c];D[U[c]]=size;

D[size]=c;U[c]=size;

if(H[r]==-1) H[r]=L[size]=R[size]=size;

else

{

L[size]=L[H[r]];R[L[H[r]]]=size;

R[size]=H[r];L[H[r]]=size;

}

size++;

}

void remove(int c)

{

int i;

for(i=D[c];i!=c;i=D[i])

L[R[i]]=L[i],R[L[i]]=R[i];

}

void resume(int c)

{

int i;

for(i=U[c];i!=c;i=U[i])

L[R[i]]=R[L[i]]=i;

}

int h()

{

int i,j,k,count=0;

bool visit
;

memset(visit,0,sizeof(visit));

for(i=R[0];i;i=R[i])

{

if(visit[i]) continue;

count++;

visit[i]=1;

for(j=D[i];j!=i;j=D[j])

{

for(k=R[j];k!=j;k=R[k])

visit[C[k]]=1;

}

}

return count;

}

void Dance(int k)

{

int i,j,c,Min,ans;

ans=h();

if(k+ans>K) return ;//仅限于此题

if(k+ans>=ak) return;

if(!R[0])

{

if(k<ak) ak=k;

return;

}

for(Min=N,i=R[0];i;i=R[i])

if(S[i]<Min) Min=S[i],c=i;

for(i=D[c];i!=c;i=D[i])

{

remove(i);

for(j=R[i];j!=i;j=R[j])

remove(j);

Dance(k+1);

for(j=L[i];j!=i;j=L[j])

resume(j);

resume(i);

}

return;

}

double d[66][66];

double dl[66*66];

int main()

{

int i,j,ncase;

double x
,y
;

int left,right,mid;

double ans;

scanf("%d",&ncase);

while(ncase--)

{

int tn;

//村庄当成列tn,救火站当成行tn 最多用K个救火站

scanf("%d%d",&tn,&K);

n=m=tn;

for(i=1;i<=m;i++)

scanf("%lf%lf",&x[i],&y[i]);

int num = 0;

for (i = 1; i <= n; ++i) {

for (j = i; j <= m; ++j) {

d[i][j] = d[j][i] = dl[num++] = dis(x[i],y[i],x[j], y[j]);

}

}

//二分答案这里要注意:如果直接left=0,right=(1<<30)直接二分 会超时

//这里要把所有距离先排序 二分枚举这些距离 AC

sort(dl, dl + num);

num = unique(dl, dl + num) - dl;

left=0;

right= num-1;

ans=dl[right];

while(left<right)

{

//DLX

for(i=0;i<=m;i++)

{

S[i]=0;

U[i]=D[i]=i;

L[i+1]=i;R[i]=i+1;

}R[m]=0;

memset(H,-1,sizeof(H));

size=m+1;

mid=(left+right)/2;

for(i=1;i<=n;i++)

{

for(j=1;j<=m;j++)

if(dl[mid]>=d[i][j]) Link(i,j);

}

ak=N;

Dance(0);

//......

if(ak<=K) {ans=min(ans,dl[mid]);right=mid;}

else left=mid+1;

}

printf("%.6lf\n",ans);

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐