HDU 3656 二分+dlx判定

Fire station

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1308    Accepted Submission(s): 434

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

给定n个城市,要修建m个防火站,使得每一个城市发生火灾所需要的最大救援时间最短。

一开始二分距离,然后枚举建边,dlx判定tle,学习别人的写法,把两点间距离的序列排序,二分下标,这样时效高了很多。

距离序列第二重循环只枚举一半wa,全部枚举ac,很不理解。

代码:

/* ***********************************************
Author :_rabbit
Created Time :2014/4/28 14:08:33
File Name :1.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
typedef long long ll;
struct Point{
    double x,y;
}city[600];
double dis[600][600],dd[500100];
double dist(Point a,Point b){
    double s=a.x-b.x,t=a.y-b.y;
    return sqrt(s*s+t*t);
}
struct DLX{
    const static int maxn=311110;
    #define FF(i,A,s) for(int i = A[s];i != s;i = A[i])
    int L[maxn],R[maxn],U[maxn],D[maxn];
    int size,col[maxn],row[maxn],s[maxn],H[maxn];
    bool vis[700];
    int ans[maxn],cnt;
    void init(int m){
        for(int i=0;i<=m;i++){
            L[i]=i-1;R[i]=i+1;U[i]=D[i]=i;s[i]=0;
        }
        memset(H,-1,sizeof(H));
        L[0]=m;R[m]=0;size=m+1;
    }
    void link(int r,int c){
         U[size]=c;D[size]=D[c];U[D[c]]=size;D[c]=size;
         if(H[r]<0)H[r]=L[size]=R[size]=size;
         else {
             L[size]=H[r];R[size]=R[H[r]];
             L[R[H[r]]]=size;R[H[r]]=size;
         }
         s[c]++;col[size]=c;row[size]=r;size++;
     }
    void del(int c){//精确覆盖
        L[R[c]]=L[c];R[L[c]]=R[c];
        FF(i,D,c)FF(j,R,i)U[D[j]]=U[j],D[U[j]]=D[j],--s[col[j]];
    }
    void add(int c){  //精确覆盖
        R[L[c]]=L[R[c]]=c;
        FF(i,U,c)FF(j,L,i)++s[col[U[D[j]]=D[U[j]]=j]];
    }
    bool dfs(int k){//精确覆盖
        if(!R[0]){
            cnt=k;return 1;
        }
        int c=R[0];FF(i,R,0)if(s[c]>s[i])c=i;
        del(c);
        FF(i,D,c){
            FF(j,R,i)del(col[j]);
            ans[k]=row[i];if(dfs(k+1))return true;
            FF(j,L,i)add(col[j]);
        }
        add(c);
        return 0;
    }
    void remove(int c){//重复覆盖
        FF(i,D,c)L[R[i]]=L[i],R[L[i]]=R[i];
    }
     void resume(int c){//重复覆盖
         FF(i,U,c)L[R[i]]=R[L[i]]=i;
     }
    int A(){//估价函数
        int res=0;
        memset(vis,0,sizeof(vis));
        FF(i,R,0)if(!vis[i]){
                res++;vis[i]=1;
                FF(j,D,i)FF(k,R,j)vis[col[k]]=1;
            }
        return res;
    }
    void dfs(int now,int &lim){//重复覆盖
        if(R[0]==0)cnt=now,lim=min(lim,now);
        else if(now+A()<lim){
            int temp=INF,c;
            FF(i,R,0)if(temp>=s[i])temp=s[i],c=i;
            FF(i,D,c){
                ans[now]=i;
                remove(i);FF(j,R,i)remove(j);
                dfs(now+1,lim);
                FF(j,L,i)resume(j);resume(i);
            }
        }
    }
}dlx;
int main()
{
     //freopen("data.in","r",stdin);
     //freopen("data.out","w",stdout);
     int T,n,m;
     cin>>T;
     while(T--){
         scanf("%d%d",&n,&m);
         for(int i=1;i<=n;i++)scanf("%lf%lf",&city[i].x,&city[i].y);
         int pp=0;
         for(int i=1;i<=n;i++)
             for(int j=1;j<=n;j++){
                 dis[i][j]=dist(city[i],city[j]);
                 dd[pp++]=dis[i][j];
             }
         sort(dd,dd+pp);
         int left=0,right=pp-1;
         while(left<right){
             int mid=(left+right)/2;
             dlx.init(n);
             for(int i=1;i<=n;i++)
                 for(int j=1;j<=n;j++)
                     if(dis[i][j]<=dd[mid])dlx.link(i,j);
             int ans=INF;
             dlx.dfs(0,ans);
             if(ans>m)left=mid+1;
             else right=mid;
         }
         printf("%.6lf\n",dd[left]);
     }
     return 0;
}

HDU 3656 二分+dlx判定,码迷,mamicode.com

时间: 2024-10-28 10:53:31

HDU 3656 二分+dlx判定的相关文章

HDU 5046 Airport(dlx)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5046 题意:n个城市修建m个机场,使得每个城市到最近进场的最大值最小. 思路:二分+dlx搜索判定. const int INF=1000000005; const int N=4444; int m; struct node { int L[N],R[N],D[N],U[N],e; int col[N]; int H[N],num[N]; int visit[N],KK; void init(in

hdu 2255 二分图带权匹配 模板题

模板+注解在 http://blog.csdn.net/u011026968/article/details/38276945 hdu 2255 代码: //KM×î´ó×îСƥÅä #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; #define INF 0x0fffffff const int MAXN

Hdu 2389 二分匹配

题目链接 Rain on your Parade Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 655350/165535 K (Java/Others)Total Submission(s): 2644    Accepted Submission(s): 823 Problem Description You’re giving a party in the garden of your villa by the sea. T

二分查找判定树

5.二分查找判定树 二分查找过程可用二叉树来描述:把当前查找区间的中间位置上的结点作为根,左子表和右子表中的结点分别作为根的左子树和右子树.由此得到的二叉树,称为描述二分查找的判定树(Decision Tree)或比较树(Comparison Tree). 注意: 判定树的形态只与表结点个数n相关,而与输入实例中R[1..n].keys的取值无关. [例]具有11个结点的有序表可用下图所示的判定树来表示. (1)二分查找判定树的组成 ①圆结点即树中的内部结点.树中圆结点内的数字表示该结点在有序表

hdu 4737 二分或暴力

http://acm.hdu.edu.cn/showproblem.php?pid=4737 Problem Description There are n numbers in a array, as a0, a1 ... , an-1, and another number m. We define a function f(i, j) = ai|ai+1|ai+2| ... | aj . Where "|" is the bit-OR operation. (i <= j)

hdu 2295 Radar(二分+DLX)

题目链接:hdu 2295 Radar 题意: 给你n个城市,m个雷达,现在最多用K个雷达,求最小半径覆盖全部的城市. 题解: 二分半径套一个DLX就行.网上随便找的一个板子 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 const double eps=1e-7; 5 6 struct Point{ 7 double x,y; 8 }city[100

[ACM] HDU 2295 Radar (二分+DLX 重复覆盖)

Radar Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2593    Accepted Submission(s): 1012 Problem Description N cities of the Java Kingdom need to be covered by radars for being in a state of

[DLX重复覆盖] hdu 3656 Fire station

题意: N个点,再点上建M个消防站. 问消防站到每个点的最大距离的最小是多少. 思路: DLX直接二分判断TLE了. 这时候一个很巧妙的思路 我们求的距离一定是两个点之间的距离 因此我们把距离都求一遍排序一下. 然后用下标二分  这样就AC了. 代码: #include"stdio.h" #include"algorithm" #include"string.h" #include"iostream" #include&quo

1065 最小正子段和 二分答案 + 判定

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1065 我的思路比较笨,我是直接二分那个答案mid 然后进行一次O(nlogn)的判定,如果能找到一个区间的和比mid小的,(当然这个区间的和也是要大于0),那就return true 进行判断如下: 处理出前缀和dp[i],对于每一个i 目标是:在前i - 1个中,查看是否有这样的一个x,使得,dp[i] - x    <=   mid,&& dp[i] -