usaco2016open gold1 split

21 篇文章 0 订阅
16 篇文章 0 订阅

Splitting the Field(Gold)

    农夫John的N(3<=N<=50,000)头奶牛分布在二维农场的不同位置上。FJ想用一个四边分别平行于x轴和y轴的矩形的栅栏把这些奶牛圈起来。并且他想用尽可能少的篱笆去把所有奶牛圈起来(在栅栏上的奶牛也被视为圈了起来)。

不幸的是,由于上季度牛奶产量低,FJ的资金紧缺。所以他想用更少的支出完成这一任务,并且他唯一可以想到的方法是用两个矩形栅栏来代替一个矩形栅栏。和原来的要求一样,这两个栅栏必须把所有奶牛圈起来(在栅栏上也行),并且他们的边需要平行于x轴和y轴(废话,和原来一样)。但这两个栅栏不允许重叠——即使仅仅是一条边重叠也不行。请注意,栅栏围成的面积是零也是合法的,也就是说,如果一个栅栏的长或宽是零,它也是合法的。

 

输入格式:(split.in):

第一行输入仅一个数N。

接下来N行,每行有两个整数,表示奶牛在农场上的位置,x和y的范围均在[1...1,000,000,000]。

 

输出格式:(split.out):

输出仅一个整数,即FJ围成的两个栅栏的面积比只用一个栅栏所围成的面积的少多少。

 

输入样例:

6

4 2

8 10

1 1

9 12

14 7

2 3

 

输出样例:

107

================================================================

乍一看题目似乎很复杂,其实就是在平面上有 n个点,要求用两个矩形把这些点围起来,求围成的两个矩形的面积比只用一个矩形所围成的面积的少多少.显然,用一个栅栏所需的面积就是(maxX-minX)*(maxY-minY),而两个栅栏的面积,我们则可以枚举.如何枚举?看似无从下手,却其实不然.可以注意一个很重要的前提条件:如果我们确定了栅栏 1的面积,另一个栅栏的面积显然就是除了栅栏 1 中的点之外的其他点的(maxX-minX)*(maxY-minY).而且为了让栅栏面积尽可能地小,栅栏的每一条边上都有奶牛,这样不会造成浪费.确定了这些之后,具体的做法是:我们先把这些点的坐标按 x轴排序,然后从左往右和从右往左分别扫一遍,求出每个点左/右边的最大和最小 y ,接着枚举每一个点作为栅栏 1 的边缘,显然栅栏 2 的面积在预处理之后容易求得.这是枚举将点的 x 坐标作为栅栏边缘的情况,还要考虑将点的 y 坐标作为边缘的情况,作一遍同样处理即可.

#include<algorithm>
#include<cstdlib>
#include<fstream>
#include<iostream>
using namespace std;
typedef long long int llint;
const int maxn = 50005;
const llint inf = 0xfffffffffffffffLL;
struct Tnode {
llint x, y, id;
} cow[maxn];
ifstream fin("split.in");
ofstream fout("split.out");
int n;
llint lmax[maxn], lmin[maxn];
llint rmax[maxn], rmin[maxn];
bool byX(Tnode, Tnode);
bool byY(Tnode, Tnode);
int main() {
fin >> n;
llint maxx, maxy, minx, miny;
maxx = maxy = -inf;
minx = miny = inf;

for(int i = 0; i != n; ++i) {
fin >> cow[i].x >> cow[i].y;
cow[i].id = i;
maxx = max(maxx, cow[i].x);
maxy = max(maxy, cow[i].y);
minx = min(minx, cow[i].x);
miny = min(miny, cow[i].y);
}

llint all_S = (maxx - minx) * (maxy - miny);
llint minSum = inf;
sort(cow, cow + n, byX);
lmax[0] = lmin[0] = cow[0].y;

for(int i = 1; i != n; ++i) {
lmax[i] = max(lmax[i - 1], cow[i].y);
lmin[i] = min(lmin[i - 1], cow[i].y);
}

rmax[n - 2] = rmin[n - 2] = cow[n - 1].y;

for(int i = n - 3; i != -1; --i) {
rmax[i] = max(rmax[i + 1], cow[i + 1].y);
rmin[i] = min(rmin[i + 1], cow[i + 1].y);
}

for(int i = 0; i != n - 1; ++i) {
if(cow[i].x == cow[i + 1].x)continue;

llint nowS1 = (cow[i].x - cow[0].x) * (lmax[i] - lmin[i]);
llint nowS2 = (cow[n - 1].x - cow[i + 1].x) * (rmax[i] - rmin[i]);
minSum = min(minSum, nowS1 + nowS2);
}

sort(cow, cow + n, byY);
lmax[0] = lmin[0] = cow[0].x;

for(int i = 1; i != n; ++i) {
lmax[i] = max(lmax[i - 1], cow[i].x);
lmin[i] = min(lmin[i - 1], cow[i].x);
}

rmax[n - 2] = rmin[n - 2] = cow[n - 1].x;

for(int i = n - 3; i != -1; --i) {
rmax[i] = max(rmax[i + 1], cow[i + 1].x);
rmin[i] = min(rmin[i + 1], cow[i + 1].x);
}

for(int i = 0; i != n - 1; ++i) {
if(cow[i].y == cow[i + 1].y)continue;

llint nowS1 = (cow[i].y - cow[0].y) * (lmax[i] - lmin[i]);
llint nowS2 = (cow[n - 1].y - cow[i + 1].y) * (rmax[i] - rmin[i]);
minSum = min(minSum, nowS1 + nowS2);
}

fout << all_S - minSum << endl;
return 0;
}
bool byX(Tnode a, Tnode b) {
return a.x < b.x || a.x == b.x && a.id < b.id;
}
bool byY(Tnode a, Tnode b) {
return a.y < b.y || a.y == b.y && a.id < b.id;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值