POJ 3348 Cows
2014-04-29 15:06
344 查看
题目大意:
一农场主想用牧场上的几颗树作为栏杆将牧场围起来防止牛逃跑,用直线将最外围的栏杆连起来可以围出一个最大面积,已知一头牛想要存活至少需要50平方米的面积。
现只有一个测例,测例中给出树的数量n(1 ≤ n ≤ 10,000),以及每棵数的坐标(x, y),其中x, y∈[-1000, 1000]而且是整数,现求出最多能样多少头牛。
题目链接
注释代码:
无注释代码:
单词解释:
fence:n, 栅栏,篱笆
plowshare:n, 犁头
sword:n, 剑
adventure:n, 历险,冒险
post:n, 标杆
pasture:n, 牧场,草场
oversee:vt, 监督,审查
一农场主想用牧场上的几颗树作为栏杆将牧场围起来防止牛逃跑,用直线将最外围的栏杆连起来可以围出一个最大面积,已知一头牛想要存活至少需要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, 监督,审查
相关文章推荐
- 本地存储(localStorage、sessionStorage、web Database)
- 计算CPU 百分比 - 基于openstack kvm 虚拟机采集片段代码分享
- DispatcherServlet与初始化主线---SpringMVC(4)
- ExtJS 之store(转)
- Android开发详解之onTouch和onClick详解
- PythonChallenge闯关游戏——第1-5关
- 使用数据绑定展示数据的局限性
- Timus 1119. Metro 动态规划
- Android ListView 几个重要属性
- char*,string,float,int 转换
- servlet
- C#函数式程序设计之泛型
- 简单数据库数据导出工具总结笔记
- JavaScript eval()
- [Android]Android 颜色大全 colors.xml
- SpringMVC深度探险(二) —— SpringMVC概览
- len获取字段长度
- 状态压缩经典题目(poj1184 nyoj81)
- python判断文件或文件夹是否存在
- android真实项目教程(五)——有时三点两点雨_by_CJJ