HDU 2295 Radar(dancin links 重复覆盖问题 +二分)

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

题解:
把雷达辐射部分作为行,辐射范围内包含的城市作为列,由于雷达辐射范围可以覆盖, 所以要该问题是舞蹈链重复覆盖问题~

#include<bits/stdc++.h>
using namespace std;

const int mn = 60;//最大行列数
const int mnn = mn*mn+2*mn+5;//最大点数
#define clr(x) memset(x, 0, sizeof(x));
#define clrlow(x) memset(x, -1, sizeof(x));

struct DLX{
    int n, m, s;
    int U[mnn], D[mnn], L[mnn], R[mnn], row[mnn], col[mnn];
    int H[mn], S[mn], vis[mnn];
    int ansed;
    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;
        s = m;
        clrlow(H);
        ansed = -1;
    }
    void push(int r, int c){
        ++S[col[++s]=c];
        row[s] = r;
        D[s] = D[c];
        U[s] =c;
        U[D[c]] = s;
        D[c] = s;
        if(H[r] < 0){
            R[s] = L[s] = H[r] = s;
        }
        else{
            R[s] = R[H[r]];
            L[s] = H[r];
            L[R[H[r]]] = s;
            R[H[r]] = s;
        }
    }
    void del(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;
    }
    int f_check(){
        int ret = 0;
        clr(vis);
        for(int c = R[0]; c != 0; c = R[c]) vis[c] = 1;
        for(int c = R[0]; c!= 0; c = R[c])
            if(vis[c]){
                ret++;
                vis[c] = 0;
                for(int i = D[c]; i != c; i = D[i])
                    for(int j = R[i]; j != i; j = R[j])
                        vis[col[j]] = 0;
            }
        return ret;
    }
    bool dance(int d, int limit){ //选取了d行 当前深度, limit 限制不能超过这个范围
        /*重复覆盖
        1、如果矩阵为空,得到结果,返回
        2、从矩阵中选择一列,以选取最少元素的列为优化方式
        3、删除该列及其覆盖的行
        4、对该列的每一行元素:删除一行及其覆盖的列,
        5、进行下一层搜索,如果成功则返回
        6、恢复现场,跳至4
        7、恢复所选择行
        */
        if(d + f_check() > limit)return 0;
        if(R[0] == 0){//全部覆盖了
        //全覆盖了之后的操作
            ansed=d;
            return 1;
        }
        int c = R[0];//表头结点指向的第一个列
        for(int i = R[0]; i != 0; i = R[i])//枚举列头指针
            if(S[i]<S[c])//找到列中元素个数最少的
                c = i;
        //remove(c);//将该列删去(精确覆盖)
        for(int i = D[c]; i != c; i = D[i]){//枚举该列的元素
            del(i);//新增(重复覆盖)
            for(int j = R[i]; j != i; j = R[j])
                del(j);//remove(Col[j])(精确覆盖)
            if(dance(d + 1, limit)) return 1;
            for(int j = L[i]; j != i; j = L[j])
                resume(j);//resume(Col[j])(精确覆盖)
            resume(i);//新增(重复覆盖)
        }
        //resume(c);(精确覆盖)
        return 0;
    }
}dlx;

struct poi{
    int x, y;
}city[60], radar[60];

double dis[60][60];

int main(){
    int T, N, M, K;
    scanf("%d", &T);
    while(T--){
        double maxn = 0, maxm = 0, l = 0, r = 0;//由于不确定半径长度,所以用二分来判断
        //cout << maxn << ' ' << maxm << endl;
        scanf("%d%d%d", &N, &M, &K);
        for(int i = 1; i <= N; i++){
            scanf("%d%d", &city[i].x, &city[i].y);
            if(city[i].x + city[i].y > maxn + maxm){//找出据原点最远的点
                maxn = city[i].x;
                maxm = city[i].y;
                //cout << maxn << ' ' << maxm << endl;
               // cout << '1' << endl;
            }
        }
        for(int i = 1; i <= M; i++){
            scanf("%d%d", &radar[i].x, &radar[i].y);
            if(radar[i].x + radar[i].y > maxn + maxm){//找出据原点最远的点
                maxn = radar[i].x;
                maxm = radar[i].y;
            }
        }
        for(int i = 1; i <= M; i++){
            for(int j = 1; j <= N; j++){
                dis[i][j] = sqrt((radar[i].x-city[j].x) * (radar[i].x-city[j].x) + (radar[i].y-city[j].y) * (radar[i].y-city[j].y));
                //cout << dis[i][j] << endl;
            }
        }
        r = sqrt(maxn * maxn + maxm * maxm);//找出据原点最远距离
        //cout << r << endl;
        //printf("%.6lf\n", r);
        while(r - l > 1e-7){//精确至小数点6位
            //printf("%.6lf\n", l);
            double mid = (r+l) / 2;
            dlx.init(M, N);//每更改完半径后都要重新初始化矩阵,因为半径改变 该范围内包含的城市也会改变
            for(int i = 1; i <= M; i++){
                for(int j = 1; j <= N; j++){
                    if(dis[i][j] <= mid)
                        dlx.push(i, j);
                }
            }
            if(dlx.dance(0, K)) r = mid;
            else l = mid;
            //
        }
        printf("%.6f\n", l);//注意输出要%f,只是由于系统兼容性问题 在提交时%lf是可以过的。。。坑死我了。。。我是个白痴
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值