DLX重复覆盖 hdu5046 Airport

传送门:点击打开链接

题意:有N个城市,现在要修K个机场,使N个城市到最近机场的最大距离最小,问K个机场应该修在哪里,机场必须修在城市中。

思路:二分N个城市到最近机场的最大距离,于是可以转换成,知道每个点,知道它的半径,能覆盖到这些点,问是否能选K个点,使得所在范围覆盖所有的点。那么这部分可以用DLX重复覆盖来做

wa点:二分的时候,l,m,r都要使用LL才行,因为可能会爆int

#include<map>
#include<set>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck printf("fuck")
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;

const int MX = 60 + 5;
const int MN = 3600 + 5;
const int INF = 0x3f3f3f3f;

struct DLX {
    int m, n, ans;
    int H[MX], S[MX], vis[MX];
    int Row[MN], Col[MN], rear;
    int L[MN], R[MN], U[MN], D[MN];

    void Init(int _m, int _n) {
        m = _m; n = _n;
        rear = n; ans = INF;
        for(int i = 0; i <= n; i++) {
            S[i] = 0;
            L[i] = i - 1;
            R[i] = i + 1;
            U[i] = D[i] = i;
        }
        L[0] = n; R[n] = 0;
        for(int i = 1; i <= m; i++) {
            H[i] = -1;
        }
    }

    void Link(int r, int c) {
        int rt = ++rear;
        Row[rt] = r; Col[rt] = c; S[c]++;

        D[rt] = D[c]; U[D[c]] = rt;
        U[rt] = c; D[c] = rt;
        if(H[r] == -1) {
            H[r] = L[rt] = R[rt] = rt;
        } else {
            int id = H[r];
            R[rt] = R[id]; L[R[id]] = rt;
            L[rt] = id; R[id] = rt;
        }
    }

    void Remove(int c) {
        for(int i = D[c]; i != c; i = D[i]) {
            R[L[i]] = R[i]; L[R[i]] = L[i];
        }
    }

    void Resume(int c) {
        for(int i = U[c]; i != c; i = U[i]) {
            R[L[i]] = L[R[i]] = i;
        }
    }

    int h() {
        int ret = 0;
        memset(vis, 0, sizeof(vis));
        for(int c = R[0]; c != 0; c = R[c]) {
            if(!vis[c]) {
                ret++;
                vis[c] = 1;
                for(int i = D[c]; i != c; i = D[i]) {
                    for(int j = R[i]; j != i; j = R[j]) {
                        vis[Col[j]] = 1;
                    }
                }
            }
        }
        return ret;
    }

    bool Dance(int cnt, int K) {
        if(cnt + h() > 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(cnt + 1, K)) return true;
            for(int j = L[i]; j != i; j = L[j]) Resume(j);
            Resume(i);
        }
        return false;
    }
} G;

LL X[MX], Y[MX], W[MX][MX];

LL dist(int i, int j) {
    return abs(X[i] - X[j]) + abs(Y[i] - Y[j]);
}

int main() {
    int T, n, K, ansk = 0; //FIN;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &K);
        for(int i = 1; i <= n; i++) {
            scanf("%I64d%I64d", &X[i], &Y[i]);
        }
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                W[i][j] = dist(i, j);
            }
        }

        LL L = 0, R = 4e9, m, ans;
        while(L <= R) {
            m = (L + R) >> 1;

            G.Init(n, n);
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= n; j++) {
                    if(W[i][j] <= m) G.Link(i, j);
                }
            }

            if(G.Dance(0, K)) {
                ans = m;
                R = m - 1;
            } else L = m + 1;
        }
        printf("Case #%d: %I64d\n", ++ansk, ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值