LA 4728 (旋转卡壳) Squares
题意:
求平面上的最远点对距离的平方。
分析:
对于这个数据量枚举肯定是要超时的。
首先这两个点一定是在凸包上的,所以可以枚举凸包上的点,因为凸包上的点要比原来的点会少很多,可最坏情况下的时间复杂度也是O(n2).
于是就有了旋转卡壳。
可以想象有两条平行直线紧紧地夹住这个凸包,那直线上的点就是对踵点对。对踵点对最多有四对,就是当凸包的两边和两直线重合的情况。
直线的角度不断变化,直线上的对踵点对也会发生变化,当直线旋转过180°后,那么凸包上所有的对踵点对也就全部遍历到了。
代码中还有很详细的注释。
里面是利用比较△(u, u+1, v) 和 △(u, u+1, v+1)的面积大小来寻找对踵点对的。因为是凸多边形,所以面积的比较转化成了两个叉积的比较,最后化简成了一个叉积PuPu+1×PvPv+1。
直接从化简出来的结果来看,如果两个向量的叉乘大于0的话,说明v正在远离直线PuPu+1,如果小于0的话说明正在靠近直线,也很容易理解。
- //#define LOCAL
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- #include <cmath>
- #include <vector>
- using namespace std;
- struct Point
- {
- int x, y;
- Point(int x=, int y=):x(x), y(y){}
- };
- typedef Point Vector;
- Point operator + (Point a, Point b) { return Point(a.x+b.x, a.y+b.y); }
- Point operator - (Point a, Point b) { return Point(a.x-b.x, a.y-b.y); }
- int Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; }
- int Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; }
- bool operator < (const Point& a, const Point& b)
- {
- return a.x < b.x || (a.x == b.x && a.y < b.y);
- }
- bool operator == (const Point& a, const Point& b)
- {
- return a.x == b.x && a.y == b.x;
- }
- int Dist2(const Point& a, const Point& b)
- { return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y); }
- vector<Point> ConvexHull(vector<Point>& p)
- {
- sort(p.begin(), p.end());
- p.erase(unique(p.begin(), p.end()), p.end());
- int n = p.size();
- int m = ;
- vector<Point> ch(n+);
- for(int i = ; i < n; ++i)
- {
- while(m > && Cross(ch[m-]-ch[m-], p[i]-ch[m-]) <= ) m--;
- ch[m++] = p[i];
- }
- int k = m;
- for(int i = n-; i >= ; --i)
- {
- while(m > k && Cross(ch[m-]-ch[m-], p[i]-ch[m-]) <= ) m--;
- ch[m++] = p[i];
- }
- if(n > ) m--;
- ch.resize(m);
- return ch;
- }
- int diameter2(vector<Point>& points)
- {
- vector<Point> p = ConvexHull(points);
- int n = p.size();
- //for(int i = 0; i < n; ++i) printf("%d %d\n", p[i].x, p[i].y);
- if(n == ) return ;
- if(n == ) return Dist2(p[], p[]);
- p.push_back(p[]);
- int ans = ;
- for(int u = , v = ; u < n; ++u)
- {// 一条直线贴住边p[u]-p[u+1]
- while(true)
- {
- // 当Area(p[u], p[u+1], p[v+1]) <= Area(p[u], p[u+1], p[v])时停止旋转
- //因为两个三角形有一公共边,所以面积大的那个点到直线距离大
- // 即Cross(p[u+1]-p[u], p[v+1]-p[u]) - Cross(p[u+1]-p[u], p[v]-p[u]) <= 0
- // 根据Cross(A,B) - Cross(A,C) = Cross(A,B-C)
- // 化简得Cross(p[u+1]-p[u], p[v+1]-p[v]) <= 0
- int diff = Cross(p[u+]-p[u], p[v+]-p[v]);
- if(diff <= )
- {
- ans = max(ans, Dist2(p[u], p[v]));
- if(diff == ) ans = max(ans, Dist2(p[u], p[v+]));
- break;
- }
- v = (v+)%n;
- }
- }
- return ans;
- }
- int main(void)
- {
- #ifdef LOCAL
- freopen("4728in.txt", "r", stdin);
- #endif
- int T;
- scanf("%d", &T);
- while(T--)
- {
- int n, x, y, w;
- scanf("%d", &n);
- vector<Point> p;
- for(int i = ; i < n; ++i)
- {
- scanf("%d%d%d", &x, &y, &w);
- p.push_back(Point(x, y));
- p.push_back(Point(x+w, y));
- p.push_back(Point(x+w, y+w));
- p.push_back(Point(x, y+w));
- }
- printf("%d\n", diameter2(p));
- }
- return ;
- }
代码君
LA 4728 (旋转卡壳) Squares的更多相关文章
- LA 4728 旋转卡壳算法求凸包的最大直径
#include<iostream> #include<cstdio> #include<cmath> #include<vector> #includ ...
- UVAL 4728 Squares(旋转卡壳)
Squares [题目链接]Squares [题目类型]旋转卡壳 &题解: 听着算法名字,感觉挺难,仔细一看之后,发现其实很简单,就是依靠所构成三角行面积来快速的找对踵点,就可以省去很多的复杂 ...
- UVALive 4728 Squares(旋转卡壳)
Squares The famous Korean IT company plans to make a digital map of the Earth with help of wireless ...
- UVA 4728 Squares(凸包+旋转卡壳)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=17267 [思路] 凸包+旋转卡壳 求出凸包,用旋转卡壳算出凸包的直 ...
- UVa 1453 - Squares 旋转卡壳求凸包直径
旋转卡壳求凸包直径. 参考:http://www.cppblog.com/staryjy/archive/2010/09/25/101412.html #include <cstdio> ...
- 1393: Robert Hood 旋转卡壳 凸包
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1393 http://poj.org/problem?id=2187 Beauty Contest ...
- POJ 3608 Bridge Across Islands --凸包间距离,旋转卡壳
题意: 给你两个凸包,求其最短距离. 解法: POJ 我真的是弄不懂了,也不说一声点就是按顺时针给出的,不用调整点顺序. 还是说数据水了,没出乱给点或给逆时针点的数据呢..我直接默认顺时针给的点居然A ...
- 【BZOJ 1069】【SCOI 2007】最大土地面积 凸包+旋转卡壳
因为凸壳上对踵点的单调性所以旋转卡壳线性绕一圈就可以啦啦啦--- 先求凸包,然后旋转卡壳记录$sum1$和$sum2$,最后统计答案就可以了 #include<cmath> #includ ...
- 【POJ 2187】Beauty Contest(凸包直径、旋转卡壳)
给定点集的最远两点的距离. 先用graham求凸包.旋(xuán)转(zhuàn)卡(qiǎ)壳(ké)求凸包直径. ps:旋转卡壳算法的典型运用 http://blog.csdn.net/hanch ...
随机推荐
- asp.net asp:TextBox控件绑定值后,获取不到新值问题解决方法
把Page_Load里绑定的代码放在 if(!IsPostBack){}里面后,即可获取到更新的值. 意思为第一次加载执行.
- mongodb 的安装历程
mongo 安装历程 mongo的安装方法有千万种,只有一种让我觉得还不错,说说安装过程中的一点心德. 方法一:源码安装,千万别用这种方法,尼马我用虚拟机编译了一下午,竟然没有编译完,强制关机,第二天 ...
- iOS开发之数据存取3-CoreData自定义数据类型
当系统提供的类型不能达到我们的使用要求时,比如我想在CoreData中存储UIColor,该怎么办呢? 这时候就要用到CoreData中非常强大的一个存储类型了:Transformable 下面将通过 ...
- Windows 进程通信 之 DDE技术
DDE (Dynamic Data Exchange,DDE)动态数据交换,是一种进程间通信机制,它最早是随着Windows由微软提出的.当前大部分软件仍旧支持DDE,但最近十年里微软已经停止发展DD ...
- uva 11029
看了别人的解法 发现了 modf 这个函数 取小数部分 /*********************************************************************** ...
- Web App之一
JSP/HTML/CSS---------View(不包含任何的数据,只作为基本的layout) JS------------------------Data(update JSP/HTML)
- java split函数 对空的处理
String str = "5,6,55,66,,,,@"; String[] chk_deep = str.split("@"); System.out.pr ...
- Lua 的数据结构
1. Arrays: 注意 #(data), # 加上 table名字 == size of data = {}; , do --行 , do --列 data[(y-)*+x] = (y-)*+x; ...
- mac上eclipse上运行word count
1.打开eclipse之后,建立wordcount项目 package wordcount; import java.io.IOException; import java.util.StringTo ...
- java基础知识回顾之java Thread类学习(十)--线程的状态以及转化使用的方法介绍
线程的概述: 线程是程序的多个执行路径,执行调度的单位,依托于进程存在.线程不仅可以共享进程的内存,而且还拥有一个属于自己的内存空间,这段内存空间叫做线程栈,是建立线程的时候由系 ...