题意:

求平面上的最远点对距离的平方。

分析:

对于这个数据量枚举肯定是要超时的。

首先这两个点一定是在凸包上的,所以可以枚举凸包上的点,因为凸包上的点要比原来的点会少很多,可最坏情况下的时间复杂度也是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的更多相关文章

  1. LA 4728 旋转卡壳算法求凸包的最大直径

    #include<iostream> #include<cstdio> #include<cmath> #include<vector> #includ ...

  2. UVAL 4728 Squares(旋转卡壳)

    Squares [题目链接]Squares [题目类型]旋转卡壳 &题解: 听着算法名字,感觉挺难,仔细一看之后,发现其实很简单,就是依靠所构成三角行面积来快速的找对踵点,就可以省去很多的复杂 ...

  3. UVALive 4728 Squares(旋转卡壳)

    Squares The famous Korean IT company  plans to make a digital map of the Earth with help of wireless ...

  4. UVA 4728 Squares(凸包+旋转卡壳)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=17267 [思路] 凸包+旋转卡壳 求出凸包,用旋转卡壳算出凸包的直 ...

  5. UVa 1453 - Squares 旋转卡壳求凸包直径

    旋转卡壳求凸包直径. 参考:http://www.cppblog.com/staryjy/archive/2010/09/25/101412.html #include <cstdio> ...

  6. 1393: Robert Hood 旋转卡壳 凸包

    http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1393 http://poj.org/problem?id=2187 Beauty Contest ...

  7. POJ 3608 Bridge Across Islands --凸包间距离,旋转卡壳

    题意: 给你两个凸包,求其最短距离. 解法: POJ 我真的是弄不懂了,也不说一声点就是按顺时针给出的,不用调整点顺序. 还是说数据水了,没出乱给点或给逆时针点的数据呢..我直接默认顺时针给的点居然A ...

  8. 【BZOJ 1069】【SCOI 2007】最大土地面积 凸包+旋转卡壳

    因为凸壳上对踵点的单调性所以旋转卡壳线性绕一圈就可以啦啦啦--- 先求凸包,然后旋转卡壳记录$sum1$和$sum2$,最后统计答案就可以了 #include<cmath> #includ ...

  9. 【POJ 2187】Beauty Contest(凸包直径、旋转卡壳)

    给定点集的最远两点的距离. 先用graham求凸包.旋(xuán)转(zhuàn)卡(qiǎ)壳(ké)求凸包直径. ps:旋转卡壳算法的典型运用 http://blog.csdn.net/hanch ...

随机推荐

  1. 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!

    // test20.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include< ...

  2. jquery ajax对特殊字符进行转义防止js注入使用示例

    在使用ajax进行留言的时候,出现了一个问题.因为留言内容写完之后,通过ajax提交内容,同时使用js把留言的内容添加到页面上来.浏览留言的时候也是通过ajax请求,然后再显示的.这样,如果有人在留言 ...

  3. 设置Eclipse智能提示

    原地址:http://blog.csdn.net/sz_bdqn/article/details/4956162 今天有点时间,研究了一下MyEclispse的智能感知的功能.刚开始使用它时总是感觉如 ...

  4. Binary Search Tree In-Order Traversal Iterative Solution

    Given a binary search tree, print the elements in-order iteratively without using recursion. Note:Be ...

  5. 移动开发之meta篇

    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable= ...

  6. JScrollPane与JPanel 滚动条 解决canvas的滚动条问题

    当用JScrollPane和JPanel显示图片时,需要将JPanel的PrefferedSize及时传递给JScrollPane,否则容易出现JScrollPane的滚动条无法与图片大小匹配的问题, ...

  7. 区间dp笔记√

    区间DP是一类在区间上进行dp的最优问题,一般是根据问题设出一个表示状态的dp,可以是二维的也可以是三维的,一般情况下为二维. 然后将问题划分成两个子问题,也就是一段区间分成左右两个区间,然后将左右两 ...

  8. Android:控件AutoCompleteTextView 客户端保存搜索历史自动提示

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  9. set集合_定长

    //set集合的操作        //便利初始化函数        NSSet *set1 = [[NSSet alloc] initWithObjects:@"aa", @&q ...

  10. 转:linux下面/usr/local和opt目录有何区别

    /usr/local下一般是你安装软件的目录,这个目录就相当于在windows下的programefiles这个目录 /opt这个目录是一些大型软件的安装目录,或者是一些服务程序的安装目录 /opt ...