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 , ...
随机推荐
- SQL SERVER 强制排序规则查询
有时会需要在2个DB之间的数据做比较, 但因为一些原因, 数据库的默认排序规则是不一样的, 例如 SELECT A.Col1, B.Col1, A.* FROM DB1.dbo.A LEFT JOIN ...
- busying
罪过 ,最近好忙 ,好久没有发表东西了, 连英语单词都写错了
- MYSQL远程登录权限设置
Mysql默认关闭远程登录权限,如下操作允许用户在任意地点登录: 1. 进入mysql,GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY ...
- android开发设置dialog的高宽
这里设置为跟屏幕一样的宽度,:看代码 dlg.show(); WindowManager.LayoutParams params = dlg.getWindow().getAttributes(); ...
- android 开发解密时出现pad block corrupted 错误
情景:在虚拟机上运行正常的,但是到我的真机上就解密失败,出现pad block corrupted ,据说是版本原因:我机器是小米3 最新版的android 4.2 出现问题的代码: privat ...
- javacript中的mvc设计模式
以下内容为原创翻译,翻译不对的地方还请原谅,凑合着看吧. 原文网址是: 来源:http://www.alexatnet.com/articles/model-view-controller-mvc-j ...
- Django 学习笔记之四 QuerySet常用方法
QuerySet是一个可遍历结构,它本质上是一个给定的模型的对象列表,是有序的. 1.建立模型: 2.数据文件(test.txt) 3.文件数据入库(默认的sqlite3) 入库之前执行 数据库同步命 ...
- linux进程管理之服务
init进程首先通过initable查看运行级别,然后运行rc.d下面的sysinit,然后调用rc,然后运行rc###连接到init.d下面的服务.自启动. chkconfig命令只是查看和设置服 ...
- Unity3D脚本中文系列教程(十)
http://dong2008hong.blog.163.com/blog/static/4696882720140312627682/?suggestedreading&wumii Unit ...
- JAVA WEB中如何让数据库连接对开发人员完全透明?
书上的技术,确实开了眼界. 列相关测试代码如下,慢慢体会开发的模式. PropsUtil package org.smart4j.chapter2.util; import java.io.FileN ...