您的位置:首页 > 其它

POJ 3348 Cows

2014-04-29 15:06 344 查看
题目大意:

一农场主想用牧场上的几颗树作为栏杆将牧场围起来防止牛逃跑,用直线将最外围的栏杆连起来可以围出一个最大面积,已知一头牛想要存活至少需要50平方米的面积。

现只有一个测例,测例中给出树的数量n(1 ≤ n ≤ 10,000),以及每棵数的坐标(x, y),其中x, y∈[-1000, 1000]而且是整数,现求出最多能样多少头牛。

题目链接

注释代码:

/*
* Problem ID : POJ 3348 Cows
* Author     : Lirx.t.Una
* Language   : C++
* Run Time   : 0 ms
* Run Memory : 264 KB
*/

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>

//maximum number of trees
//树的最大数量
#define	MAXTREEN		10000

using namespace std;

struct	Point {//平面点

int		x, y;

Point(void) {}

Point( int xx, int yy ) : x(xx), y(yy) {}

friend istream &
operator>>( istream &is, Point &p ) {//输入

is >> p.x >> p.y;

return is;
}

Point
operator-(const Point &oth)
const {//计算向量,返回向量

return Point( x - oth.x, y - oth.y );
}

int
operator*(Point oth) {//计算叉积

return x * oth.y - oth.x * y;
}

bool
operator<(Point &p) {//用于筛选y最小其次x也最小的点,即凸包中的最低最左点P0

return y < p.y || ( y == p.y && x < p.x );
}

bool
operator>=(Point &p) {//用于去掉相对于P0极角相等的离P0较近的点

return abs(x) >= abs(p.x) && abs(y) >= abs(p.y);
}
};

Point	pt[MAXTREEN];//point,表示树的点集
Point	stk[MAXTREEN];//栈,Graham算法中使用
int		top;//栈顶

void
swp( Point *ap, int i, int j ) {//交换pt数组中的两元素

Point	ptmp;

ptmp  = ap[i];
ap[i] = ap[j];
ap[j] = ptmp;
}

bool
fcmp(const Point &p1, const Point &p2) {//用于对点的排序
//对于任何两点,比较其相对于P0极角的大小可以使用叉积法

//flag = P0->P1 × P0->P2
//flag > 0表示P2极角大于P1,从图上看P2靠左、P1靠右
//flag = 0表示P1、P2、P0共线
//flag < 0表示P1极角大于P2,从图上看P1靠左、P2靠右

return ( p1 - *pt ) * ( p2 - *pt ) > 0;
}

void
graham(int n) {//Gramham扫描法,找出凸包,凸包按逆时针保存在栈stk里

int		i;

stk[0] = pt[0];
stk[1] = pt[1];
stk[2] = pt[2];

top = 2;

for ( i = 3; i < n; i++ ) {

//注意要使用>=,比>更优化,以为如果出现==的情况就意味着i、top、top - 1共线
//为了避免计算面积时多处理几步,所以只保留离top - 1较远的i而把top弹掉
while ( ( pt[i] - stk[top - 1] ) * ( stk[top] - stk[top - 1] ) >= 0 )
top--;//表示stk[top]处凹陷进去了,因此不符合要求,要弹栈
//由于弹的永远都是中间点,因此0不可能被弹,所以不用对栈判空

stk[++top] = pt[i];//总算凸了
}
}

int
dArea(void) {//double area,计算凸包的面积的两倍

int		s;
int		i;

//凸包的面积就是按照逆时针每相邻两点对P0的叉积绝对值之和
for ( s = 0, i = 1; i < top; i++ )
s +=  abs( ( stk[i] - *stk ) * ( stk[i + 1] - *stk ) );

return s;
}

int
main() {

int		n;//顶点数

int		i, j;//计数变量
int     mi;//minimum ith,最下然后最左的顶点的下标

Point	pi, pj;//临时变量

scanf("%d", &n);
if ( n < 3 ) {//判断一下特殊情况

puts("0");
return 0;
}

for ( i = 0; i < n; i++ ) cin >> pt[i];

for ( mi = 0, i = 1; i < n; i++ )
if ( pt[i] < pt[mi] )
mi = i;
swp( pt, 0, mi );//选出最下然后最左的点和0号点交换,0号点击P0
sort(pt + 1, pt + n, fcmp);//按照对P0的极角从小到大排序
for ( j = 1, i = 2; i < n; i++ ) {//!!注意:快速排序时不稳定的
//因此要从所有极角相等的点中剔除和P0距离较近的点保留距离最大的点

if ( !( ( pi = pt[i] - *pt ) * ( pj = pt[j] - *pt ) ) ) {//找出极角相等的点
//即和P0共线的点

if ( pi >= pj ) pt[j] = pt[i];//计算绝对距离
continue;
}

pt[++j] = pt[i];
}
n = j + 1;//离散化后实际可用点数有所减少

graham(n);
//牛存活面积为50,由于凸包面积是两倍的,因此牛的面积也要相应乘2
printf("%d\n", dArea() / 100);

return 0;
}


无注释代码:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>

#define	MAXTREEN		10000

using namespace std;

struct	Point {

int		x, y;

Point(void) {}

Point( int xx, int yy ) : x(xx), y(yy) {}

friend istream &
operator>>( istream &is, Point &p ) {

is >> p.x >> p.y;

return is;
}

Point
operator-(const Point &oth)
const {

return Point( x - oth.x, y - oth.y );
}

int
operator*(Point oth) {

return x * oth.y - oth.x * y;
}

bool
operator<(Point &p) {

return y < p.y || ( y == p.y && x < p.x );
}

bool
operator>=(Point &p) {

return abs(x) >= abs(p.x) && abs(y) >= abs(p.y);
}
};

Point	pt[MAXTREEN];
Point	stk[MAXTREEN];
int		top;

void
swp( Point *ap, int i, int j ) {

Point	ptmp;

ptmp  = ap[i];
ap[i] = ap[j];
ap[j] = ptmp;
}

bool
fcmp(const Point &p1, const Point &p2) {

return ( p1 - *pt ) * ( p2 - *pt ) > 0;
}

void
graham(int n) {

int		i;

stk[0] = pt[0];
stk[1] = pt[1];
stk[2] = pt[2];

top = 2;

for ( i = 3; i < n; i++ ) {

while ( ( pt[i] - stk[top - 1] ) * ( stk[top] - stk[top - 1] ) >= 0 )
top--;

stk[++top] = pt[i];
}
}

int
dArea(void) {

int		s;
int		i;

for ( s = 0, i = 1; i < top; i++ )
s +=  abs( ( stk[i] - *stk ) * ( stk[i + 1] - *stk ) );

return s;
}

int
main() {

int		n;
int		i, j;
int     mi;

Point	pi, pj;

scanf("%d", &n);
if ( n < 3 ) {

puts("0");
return 0;
}

for ( i = 0; i < n; i++ ) cin >> pt[i];

for ( mi = 0, i = 1; i < n; i++ )
if ( pt[i] < pt[mi] )
mi = i;
swp( pt, 0, mi );
sort(pt + 1, pt + n, fcmp);
for ( j = 1, i = 2; i < n; i++ ) {

if ( !( ( pi = pt[i] - *pt ) * ( pj = pt[j] - *pt ) ) ) {

if ( pi >= pj ) pt[j] = pt[i];
continue;
}

pt[++j] = pt[i];
}
n = j + 1;

graham(n);
printf("%d\n", dArea() / 100);

return 0;
}


单词解释:

fence:n, 栅栏,篱笆

plowshare:n, 犁头

sword:n, 剑

adventure:n, 历险,冒险

post:n, 标杆

pasture:n, 牧场,草场

oversee:vt, 监督,审查
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: