HDU 2295.Radar (DLX重复覆盖)

2分答案+DLX判断可行

不使用的估计函数的可重复覆盖的搜索树将十分庞大

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;

#define FOR(i,A,s)  for(int i = A[s]; i != s; i = A[i])
#define exp 1e-8

const int MAX = 111111, MAXR = 1111, MAXC = 1111;
int n, m, k, t;

struct DLX {
    int n, Size;//Size为尾指针,真正大小
    int row[MAX], col[MAX];//记录每个点的行列
    int U[MAX], D[MAX], R[MAX], L[MAX]; //4个链表
    int S[MAXC];//每列1的个数
    int ncnt, ans[MAXR];
    void init (int n) {
        this->n = n;
        //增加n+1个辅助链表,从0到n
        for (int i = 0; i <= n; i++)
            U[i] = D[i] = i, L[i] = i - 1, R[i] = i + 1;
        R[n] = 0, L[0] = n; //头尾相接
        Size = n + 1;
        memset (S, 0, sizeof S);
    }
    //逐行添加
    void addRow (int r, int columns[111]) {
        int first = Size;
        for (int i = 1; i <= n ; i++) {
            if (columns[i] == 0) continue;
            int c = i;
            L[Size] = Size - 1, R[Size] = Size + 1;
            U[Size] = U[c], D[Size] = c;//插入第c列
            D[U[c]] = Size, U[c] = Size; //注意顺序!!!
            row[Size] = r, col[Size] = c;
            Size++, S[c]++;
        }
        if (Size > first)
            R[Size - 1] = first, L[first] = Size - 1; //头尾相接
    }
    void Remove (int c) {
        //精确覆盖
//        L[R[c]] = L[c], R[L[c]] = R[c];
//        FOR (i, D, c)
//                     FOR (j, R, i)
//                            U[D[j]] = U[j], D[U[j]] = D[j], --S[col[j]];
        //重复覆盖
        for (int i = D[c]; i != c; i = D[i])
            L[R[i]] = L[i], R[L[i]] = R[i];
    }
    void Restore (int c) {
//        FOR (i, U, c)
//                     FOR (j, L, i)
//                            ++S[col[j]], U[D[j]] = j, D[U[j]] = j;
//        L[R[c]] = c, R[L[c]] = c;
        //重复覆盖
        for (int i = U[c]; i != c; i = U[i])
            L[R[i]] = R[L[i]] = i;
    }
    bool v[MAX];
    int ff()
    {
        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 dfs (int d) {
        if (d + ff() > k) return 0;
        if (R[0] == 0) {
            ncnt = d;
            return d <= k;
        }
        int c = R[0];
        for (int i = R[0]; i != 0; i = R[i])
            if (S[i] < S[c])
                c = i;
        //Remove (c);//精确覆盖
        FOR (i, D, c) {
            Remove (i);//重复覆盖
            ans[d] = row[i];
            //FOR (j, R, i) Remove (col[j]);
            FOR (j, R, i) Remove (j);
            if (dfs (d + 1) ) return 1;
            //FOR (j, L, i) Restore (col[j]);
            FOR (j, L, i) Restore (j);
            Restore (i);//重复覆盖
        }
        //Restore (c);//精确覆盖
        return 0;
    }
    bool solve (vector<int> &v) {
        v.clear();
        if (!dfs (0) ) return 0;
        for (int i = 0; i < ncnt; i++) v.push_back (ans[i]);
        return 1;
    }
} f;
struct node {
    int x, y;
} g[100], Ra[100];
int columns[111][111];
double dis[111][111];
inline double getdis (node a, node b) {
    return sqrt (double ( (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) ) );
}
bool make (double mid) {
    f.init (n);
    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= n; j++)
            columns[i][j] = dis[i][j] <= mid;
    for (int i = 1; i <= m; i++)
        f.addRow (i, columns[i]);
    return f.dfs (0);
}
int main() {
    scanf ("%d", &t);
    while (t--) {
        scanf ("%d %d %d", &n, &m, &k);
        for (int i = 1; i <= n; i++)
            scanf ("%d %d", &g[i].x, &g[i].y);
        for (int i = 1; i <= m; i++)
            scanf ("%d %d", &Ra[i].x, &Ra[i].y);
        double l = 1e9, r = 0;
        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= n; j++) {
                dis[i][j]  = getdis (Ra[i], g[j]);
                l = min (dis[i][j], l), r = max (r, dis[i][j]);
            }
        double ans = -1;
        while (r - l > 1e-7) {
            double mid = (r + l) / 2.;
            if (make (mid) ) {
                ans = mid;
                r = mid - exp;
            }
            else
                l = mid + exp;
        }
        printf ("%.6f\n", ans);
    }
    return 0;
}

时间: 2024-10-10 05:03:07

HDU 2295.Radar (DLX重复覆盖)的相关文章

【HDU 2295】DLX重复覆盖

题意:一个国家有n个城市,有m个地方可以建造雷达,最多可以建K个雷达(K>=1 && K<=m),问雷达最短的探测半径,才能使n个城市都能探测到. 思路:比较裸一点的dl,二分答案,然后算出当前状况下 重复覆盖所需的雷达的个数,判断能否满足条件. #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace st

[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

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

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

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;

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

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 这是个剑与魔法的世界.英雄和魔物同在,动荡和安定并存.但总的来说,库尔特王国是个安宁的国家,人民安居乐业,魔物也比较少.但是.总有一些魔物不时会进入城市附近,干扰人民的生活.就要有一些人出来守护居民们不被魔物侵害.魔法使艾米莉

HDOJ 2828 Lamp DLX重复覆盖

DLX重复覆盖模版题: 每个开关两个状态,但只能选一个,建2m×n的矩阵跑DLX模版.... Lamp Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 855    Accepted Submission(s): 265 Special Judge Problem Description There are several switch