[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 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

The 4th Baidu Cup final

解题思路:

题意为有m个雷达,每个雷达的覆盖范围都为以r为半径的圆,给定他们的坐标,有n个城市,给定他们的坐标,求最小的r,使得每个城市都被雷达覆盖,限制条件为最多只有k个雷达工作。

二分答案r,判断所需要的雷达数是否小于给定的k,找到最小的r。

用Dlx重复覆盖来判断。首先建图:m行,n列的矩形,也就是横坐标代表雷达,纵坐标代表城市,如果雷达与城市之间的距离小于等于当前的r,则坐标处标记为1,否则为0,这样就转化为了01矩阵,也就是解决问题能不能在这个矩阵中找出一些行(行数小于等于k),使得这些行组成的新矩阵,每列都至少有一个1(重复覆盖,每列可以有多个1).

关于精确覆盖和重复覆盖,下面转载于:http://www.cnblogs.com/jh818012/p/3252154.html

精确覆盖:

首先选择当前要覆盖的列(含1最少的列),将该列和能够覆盖到该列的行全部去掉,再枚举添加的方法。

枚举某一行r,假设它是解集中的一个,那么该行所能覆盖到的所有列都不必再搜,所以删除该行覆盖到的所有列,又由于去掉的列相当于有解,所以能够覆盖到这些列的行也不用再搜,删之。

重复覆盖:

首先选择当前要覆盖的列(同上),将该列删除,枚举覆盖到该列的所有行:对于某一行r,假设它是解集中的一个,那么该行所能覆盖到的列都不必再搜,所以删除该行覆盖到的所有列。

注意此时不用删去覆盖到这些列的行,因为一列中允许有多个1。

这里有一个A*的优化:估价函数h意义为从当前状态最好情况下需要添加几条边才能覆盖。

代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int maxn=52;
const int maxm=52;
const int maxnode=3020;
int n,m,k;

struct DLX
{
    int n,m,size;
    int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode];
    int H[maxn],S[maxn];
    int ansd,ans[maxn];

    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;
        size=m;
        for(int i=1;i<=n;i++)
            H[i]=-1;
    }

    void link(int r,int c)
    {
        ++S[Col[++size]=c];
        Row[size]=r;
        D[size]=D[c];
        U[D[c]]=size;
        U[size]=c;
        D[c]=size;
        if(H[r]<0)
            H[r]=L[size]=R[size]=size;
        else
        {
            R[size]=R[H[r]];
            L[R[H[r]]]=size;
            L[size]=H[r];
            R[H[r]]=size;
        }
    }

    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[maxnode];

    int f()//精确覆盖区估算剪枝
    {
        int ret=0;
        for(int c=R[0];c!=0;c=R[c])
            v[c]=true;
        for(int c=R[0];c!=0;c=R[c])
            if(v[c])
        {
            ret++;
            v[c]=false;
            for(int i=D[c];i!=c;i=D[i])
                for(int j=R[i];j!=i;j=R[j])
                v[Col[j]]=false;
        }
        return ret;
    }

    bool dance(int d)
    {
        if(d+f()>k)
            return false;
        if(d>k)
            return false;
        if(R[0]==0)
            return true;
        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 true;
            for(int j=L[i];j!=i;j=L[j])
                resume(j);
            resume(i);
        }
        return false;
    }
};

DLX g;
const double eps=1e-8;

struct point
{
    double x,y;
}city[maxm],radar[maxn];

double dis(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&m,&n,&k);
        for(int i=1;i<=m;i++)
            scanf("%lf%lf",&city[i].x,&city[i].y);
        for(int i=1;i<=n;i++)
            scanf("%lf%lf",&radar[i].x,&radar[i].y);
         double l=0,r=1e5;
        while(r-l>=eps)
        {
            double mid=(l+r)/2.0;
            g.init(n,m);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    if(dis(radar[i],city[j])<mid-eps)
                    g.link(i,j);
            if(g.dance(0))
                r=mid-eps;
            else
                l=mid+eps;
        }
        printf("%.6lf\n",l);
    }
    return 0;
}
时间: 2024-08-06 03:41:38

[ACM] HDU 2295 Radar (二分+DLX 重复覆盖)的相关文章

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

HDU 5046 Airport(DLX重复覆盖)

HDU 5046 Airport 题目链接 题意:给定一些机场,要求选出K个机场,使得其他机场到其他机场的最大值最小 思路:二分+DLX重复覆盖去判断即可 代码: #include <cstdio> #include <cstring> using namespace std; const int MAXNODE = 4005; const int MAXM = 65; const int MAXN = 65; const int INF = 0x3f3f3f3f; int K;

HDU 2295 舞蹈链可重复覆盖+二分

点击打开链接 题意:给了n个点和m个圆心,在用不多于k个圆的情况下,使得所有的点被覆盖,最小的圆半径多大 思路:问最小的什么什么那么用二分准没错,那么二分条件是什么呢,就是用不多于K的圆能否将所有点覆盖,覆盖这部分就是裸的舞蹈链的可重复覆盖,行为m个圆,列为n个点,然后求出的最少行小于等于K,则成立,否则不成立 #include <math.h> #include <vector> #include <stdio.h> #include <string.h>

HDU 2295 Radar( 二分+Dancing Links重复覆盖 )

题意 : 有 n 个城市 , m个站 , 你要选择 k 个站 , 每个站画一个半径为 r 的圆 , 可以覆盖所有的城市 , 一个城市可以被多个站覆盖 .求的是满足要求的最小的 r . 思路很明显了 , 首先是二分 , 将问题转化成可行性判定的问题 . 那么对于 mid , 我们将 站看成行 , 将城市看成 列 , 如果一个站和一个城市的距离小于mid , 那么对应的矩阵位置的值就1 , 否则是0 , 用dlx 重复覆盖来解决 重复覆盖和精确覆盖主要有两个区别 : 第一, remove 和 res

[DLX重复覆盖] hdu 2828 Lamp

题意: 有N个灯M个开关 每个灯的ON和OFF状态都能控制一个灯是否亮 给出N行,代表对于每个灯 哪些开关的哪个状态可以使得第i个灯亮 思路: 这里需要注意一个问题 如果开关1的ON 状态和开关2的ON状态能使得1号灯亮 那么开关1.2同时处于ON的时候 1号灯也是亮的.意思就是只要有一个开关使得灯亮,灯就亮了. 简单的DLX 重复覆盖 行为每个开关的两个状态2*m行,列为n个灯 在搜索的同时标记一下哪个开关被用过了 那么另一个状态也不能用了 代码: #include"stdio.h"

HDU 5046 Airport(DLX反复覆盖)

HDU 5046 Airport 题目链接 题意:给定一些机场.要求选出K个机场,使得其它机场到其它机场的最大值最小 思路:二分+DLX反复覆盖去推断就可以 代码: #include <cstdio> #include <cstring> using namespace std; const int MAXNODE = 4005; const int MAXM = 65; const int MAXN = 65; const int INF = 0x3f3f3f3f; int K;

HDU 3335 Divisibility dancing links 重复覆盖

分析: dlx重复覆盖的巧用,重复覆盖的原理恰好符合本题的筛选方式,即选择一个数后,该数的倍数或约数可以保证在之后的搜索中不会被选择 于是修改一下启发函数,求解最大的重复覆盖即可. 其实不一定不被选择,只是选择以后,要么达不成目标,要不达到目标,也不如不选择更优 举下面的例子 3 2 3 6 答案一看就是 2 初始的dancing links的表示是这样的 2   3   6 2    1   0   1 3    0   1   1 6    1   1   1 然后肯定先选第一列进行删 删

FZU 1686 神龙的难题(DLX重复覆盖)

FZU 1686 神龙的难题 题目链接 题意:中文题 思路:每一个1看成列,每个位置作为左上角的矩阵看成行,dlx重复覆盖即可 代码: #include <cstdio> #include <cstring> using namespace std; const int MAXNODE = 66666; const int INF = 0x3f3f3f3f; const int MAXM = 230; const int MAXN = 230; int K; struct DLX

FZU 1686 神龙的难题 DLX重复覆盖

DLX重复覆盖: 需要一个A*函数剪支 Problem 1686 神龙的难题 Accept: 462    Submit: 1401 Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description 这是个剑与魔法的世界.英雄和魔物同在,动荡和安定并存.但总的来说,库尔特王国是个安宁的国家,人民安居乐业,魔物也比较少.但是.总有一些魔物不时会进入城市附近,干扰人民的生活.就要有一些人出来守护居民们不被魔物侵害.魔法使艾米莉