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 , ...
随机推荐
- VBS基础篇 - 队列
VBS中的队列需要使用System.Collections.Queue '建立队列 Dim Que : Set Que = CreateObject("System.Collections. ...
- emulatorarm.exe已停止工作
今天使用ADT 打开android模拟器突然发现模拟器报错,[emulatorarm.exe已停止工作],昨天还是好好的,不知道为什么,重建新的模拟器还是这样. 解决办法: 更改ram大小为 512M ...
- c# 取 list前100条数据
[问] List<KeyWord> sortedList = (from a in keyWordList orderby a.Total descending select a).ToL ...
- bug集合
解决方法:vertical-align:top; 垂直对齐方式:对浮动元素无效浮动类: ie 6 7要在一行显示多个div要 给每一个元素浮动 否则会出间隙. ie6双倍边距bug 1. bug条件 ...
- 1293: [SCOI2009]生日礼物 - BZOJ
Description 小西有一条很长的彩带,彩带上挂着各式各样的彩珠.已知彩珠有N个,分为K种.简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置).某些坐标上可以没有彩珠,但多个彩 ...
- linux 下 安装 rpm 格式 的 mysql
在Linux操作系统下,安装MYSQL有两种方式: 一种tar安装方式, 另外一种是rpm安装方式. 这两种安装方式有什么区别呢?尽管我们在Linux下常用tar来压缩/解压缩文件,但MYSQL的ta ...
- json封装与解析
#include <iostream> #include <boost/property_tree/ptree.hpp> #include <boost/property ...
- Sqrt函数高效实现
转自一个Sqrt函数引发的血案 我们平时经常会有一些数据运算的操作,需要调用sqrt,exp,abs等函数,那么时候你有没有想过:这个些函数系统是如何实现的?就拿最常用的sqrt函数来说吧,系统怎么来 ...
- 官方 Animator 例子解析 Animator.MatchTarget
一.官方的解释 Animator.MatchTargetSwitch to Manual ); Parameters matchPosition The position we want the bo ...
- Web Server 和 HTTP 协议
https://toutiao.io/posts/xm2fr/preview 一直在找实习,有点什么东西直接就在evernote里面记了,也没时间来更新到这里.找实习真是个蛋疼的事,一直找的是困难模式 ...