• HDU 5046 Airport【DLX重复覆盖】


    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=5046

    题意:

    给定n个城市的坐标,要在城市中建k个飞机场,使城市距离最近的飞机场的最长距离最小,求这个最小距离。

    分析:

    最小化最大值,显然二分最大距离。然后我们将距离在范围内的两个城市建边,看能否选出k个城市,使得覆盖了所有城市。
    将点之间的关系转化成01矩阵的覆盖问题,重复覆盖,建好边套个DLX即可。
    看了鸟神博客,这里可以直接将所有距离保存在一个数组中,排序并去重,二分下标即可。这样快了很多很多!
    hdu 2295 和这题一个套路,更裸一些。
    跳舞链好强大,可惜只会用模板,这个讲的还挺清晰

    代码:

    /*************************************************************************
        > File Name: O.cpp
        > Author: jiangyuzhu
        > Mail: 834138558@qq.com
        > Created Time: Fri 08 Jul 2016 03:31:58 PM CST
     ************************************************************************/
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<map>
    using namespace std;
    #define sal(n) scanf("%I64d", &(n))
    #define sa(n) scanf("%d", &(n))
    typedef long long ll;
    const int maxn = 3600 + 5, maxc = 60 + 5, maxr = 60 + 5, inf = 0x3f3f3f3f;
    struct Node{ll x; ll y;}city[maxn];
    int L[maxn], R[maxn], D[maxn], U[maxn], C[maxn];
    int S[maxc], H[maxr], size;
    int n, m, k;
    ll d[maxr][maxc], t[maxn];
    ///不需要S域
    void Link(int r, int c)
    {
        S[c]++; C[size] = c;
        U[size] = U[c]; D[U[c]] = size;
        D[size] = c; U[c] = size;
        U[c] = size;
        if(H[r] == -1) H[r] = L[size] = R[size] = size;
        else {
            L[size] = L[H[r]]; R[L[H[r]]] = size;
            R[size] = H[r]; L[H[r]] = size;
        }
        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;
    }
    int h()
    {///用精确覆盖去估算剪枝
        int ret = 0;
        bool vis[maxc];
        memset (vis, false, sizeof(vis));
        for(int i = R[0]; i; i = R[i]){
            if(vis[i]) continue;
            ret++;
            vis[i] = true;
            for (int j = D[i]; j != i; j = D[j])
                for (int k = R[j]; k != j; k = R[k])
                    vis[C[k]] = true;
        }
        return ret;
    }
    int ans;
    bool Dance(int a) //具体问题具体分析
    {               
        if(a + h() > k) return 0;
        if(!R[0]) return a <=  k;
        int c = R[0];
        for (int i = R[0]; i; 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(a + 1)) return 1;
            for (int j = L[i]; j != i; j = L[j])
                resume(j);
            resume(i);
        }
        return 0;
    }
    void initL(int x)///col is 1~x,row start from 1
    {
        for (int i = 0; i <= x; ++i){
            S[i] = 0;
            D[i] = U[i] = i;
            L[i+1] = i; R[i] = i+1;
        }///对列表头初始化
        R[x] = 0;
        size = x + 1;///真正的元素从m+1开始
        memset (H, -1, sizeof(H));
        ///mark每个位置的名字
    }
    ll dist(int i, int j)
    {
        ll d = abs(city[i].x - city[j].x) +  abs(city[i].y - city[j].y);
        return d;
    }
    bool judge(ll mid)
    {
        initL(n);
        ans = 0x3f3f3f3f;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                if(d[i][j] <= mid){
                    Link(i, j);
                }
            }
        }
        return Dance(0);
    }
    int main (void)
    {
        int T;sa(T);
        for(int tt = 1; tt <= T; tt++){
            sa(n);sa(k);
            ll maxd = 0;
            int cnt = 0;
            for(int i = 1; i <= n; i++){
                scanf("%I64d%I64d", &city[i].x, &city[i].y);
            }
            for(int i = 1; i <= n; i++){
                for(int j = 1; j <= n; j++){
                    d[i][j] = dist(i, j);
                    t[cnt++] = d[i][j];
                }
            }
            sort(t, t + cnt);
            int ncnt = unique(t, t + cnt) - t;
            ll l = -1, r = ncnt;
            while(r - l > 1){
                ll mid = (l + r) / 2;
                if(judge(t[mid])) r = mid;
                else l = mid;
            }
            printf("Case #%d: %I64d
    ", tt, t[r]);
        }
        return 0;
    }
    
    
    
    
  • 相关阅读:
    把redhat5.4-linux2.6.18内核升级到2.6.24 vmware虚拟机中
    webdeploy 使用总结(二)
    System.Web.UI.Page 详解(转)
    Dapper常用方法总结
    webdeploy 使用总结(一)
    Log4Net 详解(转)
    C# 日志工具汇总(转)
    Global.asax 详解(转)
    Transfer与Redirect区别(转)
    web.config配置节system.webServer的子元素详细介绍
  • 原文地址:https://www.cnblogs.com/Tuesdayzz/p/5758613.html
Copyright © 2020-2023  润新知