HDU_2295_Radar(DancingLinksX重复覆盖+二分)

17 篇文章 0 订阅
11 篇文章 0 订阅

Radar

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3333    Accepted Submission(s): 1285


Problem Description
N cities of the Java Kingdom need to be covered by radars for being in a state of war. Since the kingdom has M radar stations but only K operators, we can at most operate K radars. All radars have the same circular coverage with a radius of R. Our goal is to minimize R while covering the entire city with no more than K radars.
 

Input
The input consists of several test cases. The first line of the input consists of an integer T, indicating the number of test cases. The first line of each test case consists of 3 integers: N, M, K, representing the number of cities, the number of radar stations and the number of operators. Each of the following N lines consists of the coordinate of a city.
Each of the last M lines consists of the coordinate of a radar station.

All coordinates are separated by one space.
Technical Specification

1. 1 ≤ T ≤ 20
2. 1 ≤ N, M ≤ 50
3. 1 ≤ K ≤ M
4. 0 ≤ X, Y ≤ 1000
 

Output
For each test case, output the radius on a single line, rounded to six fractional digits.
 

Sample Input
  
  
1 3 3 2 3 4 3 1 5 4 1 1 2 2 3 3
 

Sample Output
  
  
2.236068
 

Source
 

Recommend
lcy



DancingLinksX重复覆盖+二分

题意

给出一堆城市和雷达的坐标

雷达有一个覆盖范围

求所有城市被雷达覆盖时,雷达的最小覆盖半径


做法

二分一个雷达的半径

雷达作为行,城市作为列

雷达覆盖范围内的城市对应一个1

然后DancingLinksX重复覆盖即可

特别注意DancingLinksX重复覆盖的模板经过了A*优化

如果没有优化会TLE而且貌似所有的重复覆盖都用了这个优化


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
using namespace std;

const int MN=55;
const int MM=55;
const int MNN=MN*MM+MM; //最大点数

int n,m,k;//n城市m雷达

struct DLX
{
    int n,m,si;//n行数m列数si目前有的节点数
    //十字链表组成部分
    int U[MNN],D[MNN],L[MNN],R[MNN],Row[MNN],Col[MNN];
    //第i个结点的U向上指针D下L左R右,所在位置Row行Col列
    int H[MN],S[MM]; //记录行的选择情况和列的覆盖情况
    int ansd,ans[MN];
    int mk;  //最大的可选行数
    void init(int _n,int _m)  //初始化空表
    {
        n=_n;
        m=_m;
        for(int i=0;i<=m;i++) //初始化第一横行(表头)
        {
            S[i]=0;
            U[i]=D[i]=i;      //目前纵向的链是空的
            L[i]=i-1;
            R[i]=i+1;         //横向的连起来
        }
        R[m]=0;L[0]=m;
        si=m;                 //目前用了前0~m个结点
        for(int i=1;i<=n;i++)
            H[i]=-1;
    }
    void link(int r,int c)    //插入点(r,c)
    {
        ++S[Col[++si]=c];     //si++;Col[si]=c;S[c]++;
        Row[si]=r;
        D[si]=D[c];
        U[D[c]]=si;
        U[si]=c;
        D[c]=si;
        if(H[r]<0)
            H[r]=L[si]=R[si]=si;
        else
        {
            R[si]=R[H[r]];
            L[R[H[r]]]=si;
            L[si]=H[r];
            R[H[r]]=si;
        }
    }
    void remove(int c)
    {
        for(int i=D[c];i!= c;i= D[i])
            L[R[i]]=L[i],R[L[i]]=R[i];
    }
    void resume(int c)
    {
        for(int i=U[c];i!= c;i=U[i])
            L[R[i]]=R[L[i]]=i;
    }
    bool v[MNN];
    int h() //估值
    {
        int ret=0;
        for(int c=R[0];c!=0;c=R[c])
            v[c]=1;
        for(int c=R[0];c!=0;c=R[c])
            if(v[c])
            {
                ret++;
                v[c]=0;
                for(int i=D[c];i!=c;i=D[i])
                    for(int j=R[i];j!=i;j=R[j])
                        v[Col[j]]=0;
            }
        return ret;

    }
    bool dance(int d)
    {
        if(d+h()>mk)  //利用A*优化
            return 0;
        if(R[0]==0)
            return d<=mk;
        int c=R[0];
        for(int i=R[0];i!=0;i=R[i])
            if(S[i]<S[c])
                c=i;
        for(int i=D[c];i!=c;i=D[i])
        {
            remove(i);
            for(int j=R[i];j!=i;j=R[j])
                remove(j);
            if(dance(d+1))
                return 1;
            for(int j=L[i];j!=i;j=L[j])
                resume(j);
            resume(i);
        }
        return 0;
    }
}dlx;

struct Node
{
    int x,y;
}radar[MN],city[MM];
double dis[MM][MN];

const double eps=1e-8;
bool work(double mi)
{
    dlx.init(m,n);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            if(dis[i][j]<mi+eps)
                dlx.link(i,j);
    return dlx.dance(0);

}
double bs()
{
    double lo=0,hi=1500.0;
    double mid,ans=1000000;
    while(hi-lo>eps)
    {
        mid=(lo+hi)/2.0;
        if(work(mid))
        {
            ans=min(ans,mid);
            hi=mid;
        }
        else
            lo=mid;
    }
    return ans;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&k);
        dlx.mk=k;
        for(int i=1;i<=n;i++)
            scanf("%d%d",&city[i].x,&city[i].y);
        for(int i=1;i<=m;i++)
            scanf("%d%d",&radar[i].x,&radar[i].y);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                dis[j][i]=sqrt(1.0*(city[i].x-radar[j].x)*(city[i].x-radar[j].x)
                               +(city[i].y-radar[j].y)*(city[i].y-radar[j].y));
        printf("%.6lf\n",bs());
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值