HDU 4946 共线凸包
题目大意:
一些点在一张无穷图上面,每个点可以控制一些区域,这个区域满足这个点到达这个区域的时间严格小于其他点。求哪些点能够控制无穷面积的区域。
题目思路:
速度小的控制范围一定有限。
速度最大当且仅当在凸包上才能够控制无穷区域。可以通过,任意两个点中垂线为界,左右各控制一半,判断出凸包内的点仅能控制有限区域。
特判:
速度最大且在同一个点上的点均不能控制无穷区域,但是要加入凸包计算。
速度最大为0不能控制无穷区域。
对于共线凸包(Graham),(代码中有解释)
均不能存在重点!可用map判重。
1、按极角坐标序排
缺点:需要将最后一条边上的点逆序排,才能够将最后一边共线点加入凸包。
2、按水平序排。
缺点:若所有点在一条直线上,会产生将所有点入凸包1~n~2的情况,需要特判,当然本题只是用到这些点,无需判断是否重复出现。
极角序:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <map>
#include <deque>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define INF 0x3f3f3f3f using namespace std; const int MAXN = ;
const double eps = 1e-;
const double PI = acos(-1.0); int tx,ty,tv,maxv,n,N,cas;
bool pd[MAXN]; int sgn(double x)
{
if(fabs(x) < eps) return ;
if(x < ) return -;
return ;
}
struct Point
{
double x,y;
int re;
Point(){}
Point(double _x, double _y): x(_x),y(_y) {}
Point operator -(const Point &B) const
{
return Point(x-B.x, y-B.y);
}
Point operator +(const Point &B) const //向量相加
{
return Point(x+B.x, y+B.y);
}
double operator ^(const Point &B) const //叉积
{
return x*B.y - y*B.x;
}
double operator *(const Point &B) const //点积
{
return x*B.x + y*B.y;
}
bool operator ==(const Point &B) const
{
return fabs(B.x-x)<eps && fabs(B.y-y)<eps;
}
bool operator !=(const Point &B) const
{
return !((*this) == B);
}
double norm()//向量的模
{
return sqrt(x*x+y*y);
}
void transXY(double B) //绕原点逆时针旋转B弧度
{
double tx = x, ty = y;
x = tx*cos(B) - ty*sin(B);
y = tx*sin(B) + ty*cos(B);
}
void input() //读入只能用double读入
{
scanf("%lf%lf",&x,&y);
}
}; struct Line
{
Point s,e;
Line(){}
Line(Point _s, Point _e)
{
s=_s; e=_e;
}
}; double dist(Point a, Point b)
{
return sqrt((a-b)*(a-b));
} //判断点在线段上
bool OnS(Point A, Line a)
{
return
sgn((a.s-A)^(a.e-A)) == &&
sgn((A.x-a.s.x)*(A.x-a.e.x)) <= &&
sgn((A.y-a.s.y)*(A.y-a.e.y)) <= ;
} //求凸包 Graham算法
//点的编号0~n-1
//返回凸包结果Stack[0~top-1]为凸包的编号
//一个点或两个点 则凸包为一或二个点
int Stack[MAXN],top;
Point vertex[MAXN];
bool Graham_cmp(Point A, Point B)
{
double tmp=(A-vertex[])^(B-vertex[]);
if(sgn(tmp) > ) return ;
if(sgn(tmp) == && sgn(dist(A,vertex[])-dist(B,vertex[])) <= ) return ;
return ;
}
void Graham(int n)
{
int k=;
for(int i=; i<n; i++)
if((vertex[k].y>vertex[i].y) || (vertex[k].y==vertex[i].y && vertex[k].x>vertex[i].x))
k=i;
swap(vertex[], vertex[k]);
sort(vertex+, vertex+n, Graham_cmp);
if(n == )
{
top=;
Stack[]=;
return;
}
if(n == )
{
top=;
Stack[]=;
Stack[]=;
return;
} int tmp;
for(tmp=n-; tmp> && sgn((vertex[]-vertex[tmp])^(vertex[]-vertex[tmp-])) == ; tmp--);
reverse(vertex+tmp,vertex+n);//最后一条边倒序 Stack[]=;
Stack[]=;
top=;
for(int i=; i<n; i++)
{
while(top > && (vertex[i] == vertex[Stack[top-]] || sgn((vertex[Stack[top-]]-vertex[Stack[top-]])^(vertex[i]-vertex[Stack[top-]])) < ))//相同点只进栈一次 同一条线上的点也进栈
top--;
Stack[top++]=i;
}
} int main()
{
// freopen("1002.in","r",stdin);
// freopen("1002p.out","w",stdout);
while(scanf("%d",&N)!=EOF && N)
{
memset(pd,,sizeof(pd));
n=;
maxv=-;
for(int i=; i<N; i++)
{
scanf("%d%d%d",&tx,&ty,&tv);
if(maxv==tv)
{
vertex[n].x=tx;
vertex[n].y=ty;
vertex[n].re=i;
n++;
}
else
if(maxv<tv)
{
maxv=tv;
n=;
vertex[n].x=tx;
vertex[n].y=ty;
vertex[n].re=i;
n++;
}
}
Graham(n); for(int i=; i<top; i++)
pd[vertex[Stack[i]].re]=; for(int i=; i<n; i++)//去掉相同点
for(int j=i+; j<n; j++)
if(vertex[i]==vertex[j])
{
pd[vertex[i].re]=;
pd[vertex[j].re]=;
} printf("Case #%d: ",++cas);
for(int i=; i<N; i++)
{
if(maxv==) printf("");
else printf("%d",pd[i]);
}
printf("\n");
}
return ;
} /*
0 0 1
0 1
0 1
1 1
2 1
3 1
1 1 */
水平序:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <map>
#include <deque>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define INF 0x3f3f3f3f using namespace std; const int MAXN = ;
const double eps = 1e-;
const double PI = acos(-1.0); int tx,ty,tv,maxv,n,N,cas;
int pd[MAXN]; int sgn(double x)
{
if(fabs(x) < eps) return ;
if(x < ) return -;
return ;
}
struct Point
{
double x,y;
int re;
Point(){}
Point(double _x, double _y): x(_x),y(_y) {}
Point operator -(const Point &B) const
{
return Point(x-B.x, y-B.y);
}
Point operator +(const Point &B) const //向量相加
{
return Point(x+B.x, y+B.y);
}
double operator ^(const Point &B) const //叉积
{
return x*B.y - y*B.x;
}
double operator *(const Point &B) const //点积
{
return x*B.x + y*B.y;
}
bool operator ==(const Point &B) const
{
return fabs(B.x-x)<eps && fabs(B.y-y)<eps;
}
bool operator !=(const Point &B) const
{
return !((*this) == B);
}
double norm()//向量的模
{
return sqrt(x*x+y*y);
}
void transXY(double B) //绕原点逆时针旋转B弧度
{
double tx = x, ty = y;
x = tx*cos(B) - ty*sin(B);
y = tx*sin(B) + ty*cos(B);
}
bool operator<(const Point B) const
{
return(x<B.x || (x==B.x && y<B.y));
}
void input() //读入只能用double读入
{
scanf("%lf%lf",&x,&y);
}
}; struct Line
{
Point s,e;
Line(){}
Line(Point _s, Point _e)
{
s=_s; e=_e;
}
}; double dist(Point a, Point b)
{
return sqrt((a-b)*(a-b));
} //判断点在线段上
bool OnS(Point A, Line a)
{
return
sgn((a.s-A)^(a.e-A)) == &&
sgn((A.x-a.s.x)*(A.x-a.e.x)) <= &&
sgn((A.y-a.s.y)*(A.y-a.e.y)) <= ;
} //求凸包 Graham算法
//点的编号0~n-1
//返回凸包结果Stack[0~top-1]为凸包的编号
//一个点或两个点 则凸包为一或二个点
int Stack[MAXN],top;
Point vertex[MAXN];
bool Graham_cmp(Point A, Point B)
{
return A.y<B.y || (A.y == B.y && A.x<B.x);
}
void Graham(int n)
{
sort(vertex, vertex+n, Graham_cmp);
top=;
for(int i=; i<n; i++)
{
while(top > && sgn((vertex[Stack[top-]]-vertex[Stack[top-]])^(vertex[i]-vertex[Stack[top-]])) < )//改为<即可
top--;
Stack[top++]=i;
}
int tmp=top;
for(int i=n-; i>=; i--)
{
while(top > tmp && sgn((vertex[Stack[top-]]-vertex[Stack[top-]])^(vertex[i]-vertex[Stack[top-]])) < )
top--;
Stack[top++]=i;
}
if(n>) top--;
} int main()
{
freopen("1002.in","r",stdin);
freopen("1002p.out","w",stdout);
map<Point,int> mapp;
while(scanf("%d",&N)!=EOF && N)
{
memset(pd,-,sizeof(pd));
n=;
maxv=-;
for(int i=; i<=N; i++)
{
scanf("%d%d%d",&tx,&ty,&tv);
if(maxv==tv && mapp[Point(tx,ty)]>)
{
pd[mapp[Point(tx,ty)]]=;
pd[i]=;
continue;
}
if(maxv==tv)
{
vertex[n].x=tx;
vertex[n].y=ty;
vertex[n].re=i;
mapp[vertex[n]]=i;
n++;
}
if(maxv<tv)
{
mapp.clear();
maxv=tv;
n=;
vertex[n].x=tx;
vertex[n].y=ty;
vertex[n].re=i;
mapp[vertex[n]]=i;
n++;
}
} Graham(n); for(int i=; i<top; i++)
if(pd[vertex[Stack[i]].re]==-)
pd[vertex[Stack[i]].re]=; printf("Case #%d: ",++cas);
for(int i=; i<=N; i++)
if(maxv==) printf("");
else
{
if(pd[i]<=) printf("");
else printf("");
}
printf("\n");
}
return ;
} /*
0 0 1
0 1
0 0
0 1
0 1
0 0 1
0 1
0 1
1 1
2 1
3 1
1 1 */
水平序优化:(可以解决重点+共线凸包问题)
vis判水平序的点是否访问过,防止一条线的情况。
pd判是否重点,在水平排序后相邻的一定相邻!写的还算漂亮。毕竟map太暴力了。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <utility>
#include <vector>
#include <queue>
#include <map>
#include <set>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define MAXN 505
#define eps 1e-4 using namespace std; struct Point{
double x,y;
int res;
Point(){}
Point(double _x, double _y): x(_x),y(_y){}
double operator^(Point A)
{
return x*A.y-A.x*y;
}
Point operator -(const Point A) const
{
return Point(x-A.x,y-A.y);
}
}vertex[MAXN]; int Stack[MAXN],top;
int N,n,x,y,v,Case;
bool vis[MAXN],pd[MAXN]; inline double dist(Point A)
{
return sqrt(A.x*A.x+A.y*A.y);
} int sgn(double x)
{
if(fabs(x)<eps) return ;
if(x<) return -;
return ;
} bool cmp(Point A, Point B)
{
return A.y<B.y || (A.y==B.y && A.x<B.x);
} void Graham(int n)
{
sort(vertex,vertex+n,cmp);
for(int i=; i<n-; i++)
if(sgn(dist(vertex[i]-vertex[i+]))==)
pd[vertex[i].res]=pd[vertex[i+].res]=;
top=;
for(int i=; i<n; i++)
{
while(top> && (sgn(dist(vertex[Stack[top-]]-vertex[Stack[top-]]))== || sgn((vertex[Stack[top-]]-vertex[Stack[top-]])^(vertex[i]-vertex[Stack[top-]]))<))
vis[Stack[--top]]=;
Stack[top++]=i;
vis[i]=;
}
int tmp=top;
for(int i=n-; i>=; i--)
{
while(top>tmp && (sgn(dist(vertex[Stack[top-]]-vertex[Stack[top-]]))== || sgn((vertex[Stack[top-]]-vertex[Stack[top-]])^(vertex[i]-vertex[Stack[top-]]))<))
vis[Stack[--top]]=;
if(!vis[i]) Stack[top++]=i;
}
//if(n>1) top--;
} int main()
{
while(scanf("%d",&N)!=EOF && N)
{
int maxv=-;
for(int i=; i<N; i++)
{
scanf("%d%d%d",&x,&y,&v);
if(v<maxv) continue;
if(v>maxv)
{
maxv=v;
n=;
}
vertex[n].x=x;
vertex[n].y=y;
vertex[n].res=i;
n++;
}
memset(vis,,sizeof(vis));
memset(pd,,sizeof(pd));
Graham(n);
// for(int i=0; i<top; i++)
// printf("%f %f\n",vertex[Stack[i]].x,vertex[Stack[i]].y);
printf("Case #%d: ",++Case);
memset(vis,,sizeof(vis));
if(maxv>)
{
for(int i=; i<top; i++)
vis[vertex[Stack[i]].res]=;
}
for(int i=; i<N; i++)
printf("%d",vis[i]&&pd[i]);
printf("\n");
}
return ;
}
HDU 4946 共线凸包的更多相关文章
- HDU 4946 Area of Mushroom 凸包 第八次多校
题目链接:hdu 4946 题意:一大神有N个学生,各个都是小神,大神有个二次元空间,每一个小神都有一个初始坐标,如今大神把这些空间分给徒弟们,规则是假设这个地方有一个人比谁都先到这,那么这个地方就是 ...
- HDU 4946 凸包
给你n个点,具有速度,一个位置如果有其他点能够先到,则不能继续访问,求出里面这些点哪些点是能够无限移动的. 首先我们考虑到,一个速度小的和一个速度大的,速度小的必定只有固定他周围的一定区域是它先到的, ...
- HDU 5928 DP 凸包graham
给出点集,和不大于L长的绳子,问能包裹住的最多点数. 考虑每个点都作为左下角的起点跑一遍极角序求凸包,求的过程中用DP记录当前以j为当前末端为结束的的最小长度,其中一维作为背包的是凸包内侧点的数量.也 ...
- HDU 4946 Area of Mushroom 共线凸包
题意是在二维平面上 给定n个人 每一个人的坐标和移动速度v 若对于某个点,仅仅有 x 能最先到达(即没有人能比x先到这个点或者同一时候到这个点) 则这个点称作被x占有 若有人能占有无穷大的面积 则输出 ...
- hdu 4946 Area of Mushroom(凸包)
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4946 Area of Mushroom Time Limit: 2000/1000 MS (Java/Ot ...
- HDU 4946 Area of Mushroom(构造凸包)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4946 题目大意:在一个平面上有n个点p1,p2,p3,p4....pn,每个点可以以v的速度在平面上移 ...
- HDU 4946 Area of Mushroom 凸包
链接:pid=4946">http://acm.hdu.edu.cn/showproblem.php?pid=4946 题意:有n个人.在位置(xi,yi),速度是vi,假设对于某个点 ...
- hdu 4946 凸包注意重点
http://acm.hdu.edu.cn/showproblem.php?pid=4946 给你n个点的坐标和速度,如果一个点能够到达无穷远处,且花费的时间是最少的,则此点输出1,否则输出0. 每个 ...
- hdu 4946 Area of Mushroom (凸包,去重点,水平排序,留共线点)
题意: 在二维平面上,给定n个人 每个人的坐标和移动速度v 若对于某个点,只有 x 能最先到达(即没有人能比x先到这个点或者同时到这个点) 则这个点称作被x占有,若有人能占有无穷大的面积 则输出1 , ...
随机推荐
- 一点关于Ajax和一个等待图标的显示
一点关于Ajax和一个等待图标的显示 1.首先Ajax是asynchronous Java-Script and XML的简写.翻译过来就是异步的JS和XML. 2它的优点就是能不更新页面的情况下,得 ...
- 2876: [Noi2012]骑行川藏 - BZOJ
Description 蛋蛋非常热衷于挑战自我,今年暑假他准备沿川藏线骑着自行车从成都前往拉萨.川藏线的沿途有着非常美丽的风景,但在这一路上也有着很多的艰难险阻,路况变化多端,而蛋蛋的体力十分有限,因 ...
- hihocoder #1301 : 筑地市场 数位dp+二分
题目链接: http://hihocoder.com/problemset/problem/1301?sid=804672 题解: 二分答案,每次判断用数位dp做. #include<iostr ...
- 新建标准mavenWeb工程以及Maven的web应用标准目录结构建议
到现在为止,使用Maven结构的Web工程越来越多,因此在此介绍一下通过Maven来构建项目的相关知识. 文档主要分为两部分: 1.如何通过maven来构建多模块的web项目 ...
- 【BZOJ】【2693】JZPTAB
莫比乌斯反演 PoPoQQQ讲义第5题,是BZOJ 2154的升级版(多次询问) 题解:http://blog.csdn.net/popoqqq/article/details/42078725 WA ...
- Matlab与微积分计算
一.极限问题的解析解 1.1 单变量函数的极限 格式1: L= limit( fun, x, x0) 格式2: L= limit( fun, x, x0, ‘left’ 或 ‘right’) > ...
- 剑指offer--面试题9
题目一:求斐波那契数列第n项 自己所写代码如下: #include "stdafx.h" #include<iostream> long Fibonacci(unsig ...
- android 解析XML方式(三)
上一节中,我们使用SAX方式解析xml文档, SAX方式是基于事件驱动的.当然android的事件机制是基于回调函数的.在这一节中,我们用另外一种方式解析xml文档,这种方式也是基于事件驱动的,与SA ...
- log4j使用感受
1.为什么使用日志? 日志可以记录项目中的重要信息,关键输出信息,异常信息,为项目上线后期维护提供方便,在项目开发中尽量养成习惯写日志,而不是System.out.println()打印,不过在jun ...
- sublime 复制黏贴等快捷键修改
在 keyboard-binding user 里 增加个人配置来覆盖默认配置 [ { "keys": ["ctrl+z"], "command&qu ...