Cover Point (DP)

Cover

Time Limit: 1000MS Memory Limit: 65536K
You are given ​N points in the coordinate system. They need to be covered with one or more rectangles, such that the following conditions are met:
● The sides of each rectangle are parallel with the coordinate axes,
● The center of each rectangle is in the origin, i.e. point (0, 0),
● Each given point is located either inside of the rectangle or on its boundaries.
Of course, it is possible to cover all the points using only one rectangle, but this rectangle could have a very large surface area. Our goal is to find a selection of required rectangles such that the sum of their surface areas is minimal

Input

The first line of input contains the integer ​N ​ (1 ≤ ​N ​ ≤ 5000), the number of points.
Each of the following ​N lines contains two integers ​X and ​Y (-50 000 000 ≤ ​X, Y ≤ 50 000 000, ​XY ​ ≠ 0), the coordinates of each point

Output

You must output the required minimal sum of surface areas of the rectangles.

Sample Input

2
1 1
-1 -1

3
-7 19
9 -30
25 10

6
1 20
3 17
5 15
8 12
9 11
10 10

Sample Output

4
2080
760


题意:

在坐标系中
定义矩形是以原点为中心的。
给出n个点,
让矩形覆盖点,即点在矩形内部或边缘上
可用任意个矩形,求这些矩形的最小面积和


题解:

这些矩形可互相叠加,重复部分面积时要计算的,所以时矩形面积变小的方法就是让一些点公用一个矩形。
输入预处理:
将所有的点排序,若以某个点为一个矩形的顶点时,把这个矩形可以覆盖的点都删去。 O(N2) O ( N 2 )
然后对于剩下的点dp,开一维数组dp[5005]
dp[i]表示更新到第i个点时的最小面积
初始化dp[i]为合并第一个点到第i个点

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
class point : public pair<ll, ll>
{
public:
    point() {}
    inline point(ll x, ll y)
    {
        first = x;second = y;
    }
    inline constexpr ll get_area()
    {
        return first * second;
    }
    inline point operator -(const point&b)const
    {
        return point(abs(first - b.first), abs(second - b.second));
    }
    inline point merge(const point&b)const
    {
        return point(max(first, b.first), max(second, b.second));
    }
};
vector<point>v, s;
ll dp[5050];
int main()
{
    int N;
    v.clear();
    scanf("%d", &N);
    for (int i = 0; i < N; i++)
    {
        ll a, b;
        scanf("%lld%lld", &a, &b);
        v.push_back(point(abs(a), abs(b)));
    }
    sort(v.begin(), v.end());
    for (int i = 0; i < v.size(); i++)
    {
        for (int j = i + 1; j < v.size(); j++)
        {
            if (v[j].first >= v[i].first&&v[j].second >= v[i].second)
            {
                v[i] = point(0, 0);
            }
        }
    }
    sort(v.begin(), v.end());
    s.clear();
    s.insert(s.begin(), upper_bound(v.begin(), v.end(), point(0, 0)), v.end());
    for (int i = 0; i < s.size(); i++)
    {
        dp[i] = (s[0].merge(s[i])).get_area();
    }
    for (int i = 0; i < s.size(); i++)
    {
        for (int j = i + 1; j < s.size(); j++)
        {
            dp[j] = min(dp[j], dp[i] + (s[i + 1].merge(s[j])).get_area());
        }
    }
    printf("%lld\n", dp[s.size() - 1] * 4);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值