【BZOJ1052】[HAOI2007]覆盖问题

【BZOJ1052】[HAOI2007]覆盖问题

题面

bzoj

洛谷

题解

二分答案是显然的。

算一下包含所有的点的最小矩形的范围\((x1,y1)\)\((x2,y2)\)

贪心思考一下肯定是把塑料薄膜其中一个角放在此矩形上的

然后\(dfs\)判一下即可

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath> 
#include <algorithm>
using namespace std; 
inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (!isdigit(ch) && ch != '-') ch = getchar(); 
    if (ch == '-') w = -1, ch = getchar(); 
    while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); 
    return w * data; 
} 
void chkmax(int &x, int y) { if (x < y) x = y; } 
void chkmin(int &x, int y) { if (x > y) x = y; } 
const int MAX_N = 20005; 
int N, vis[MAX_N]; 
pair<int, int> p[MAX_N]; 
#define x first 
#define y second
void cover(int x1, int x2, int y1, int y2, int id) { 
    for (int i = 1; i <= N; i++) 
        if (!vis[i] && x1 <= p[i].x && p[i].x <= x2 && y1 <= p[i].y && p[i].y <= y2) 
            vis[i] = id; 
} 
void uncover(int id) { for (int i = 1; i <= N; i++) if (vis[i] == id) vis[i] = 0; } 
bool dfs(int tot, int L) { 
    int _x[2], _y[2]; _x[0] = _y[0] = 2e9, _x[1] = _y[1] = -2e9; 
    for (int i = 1; i <= N; i++)
        if (!vis[i])
            chkmin(_x[0], p[i].x), chkmax(_x[1], p[i].x), chkmin(_y[0], p[i].y), chkmax(_y[1], p[i].y);
    if (max(_x[1] - _x[0], _y[1] - _y[0]) <= L) return 1;
    if (tot == 3) return 0; 
    for (int i = 0; i < 2; i++)
        for (int j = 0; j < 2; j++) {
            if (i == 0) {
                if (j == 0) cover(_x[0], _x[0] + L, _y[0], _y[0] + L, tot); 
                else cover(_x[0], _x[0] + L, _y[1] - L, _y[1], tot); 
            } else { 
                if (j == 0) cover(_x[1] - L, _x[1], _y[0], _y[0] + L, tot); 
                else cover(_x[1] - L, _x[1], _y[1] - L, _y[1], tot); 
            }
            if (dfs(tot + 1, L)) return 1; 
            uncover(tot); 
        } 
    return 0; 
}
bool check(int L) {
    memset(vis, 0, sizeof(vis));
    return dfs(1, L); 
} 
int main () {
    N = gi(); for (int i = 1; i <= N; i++) p[i].x = gi(), p[i].y = gi();
    int l = 0, r = 2e9, ans = 2e9;
    while (l <= r) {
        int mid = ((long long)l + r) >> 1ll;
        if (check(mid)) r = mid - 1, ans = mid;
        else l = mid + 1; 
    }
    printf("%d\n", ans); 
    return 0; 
} 

转载于:https://www.cnblogs.com/heyujun/p/10179259.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值