题目大意:

  一些点在一张无穷图上面,每个点可以控制一些区域,这个区域满足这个点到达这个区域的时间严格小于其他点。求哪些点能够控制无穷面积的区域。

题目思路:

  速度小的控制范围一定有限。

  速度最大当且仅当在凸包上才能够控制无穷区域。可以通过,任意两个点中垂线为界,左右各控制一半,判断出凸包内的点仅能控制有限区域。

   

  特判:

    速度最大且在同一个点上的点均不能控制无穷区域,但是要加入凸包计算。

    速度最大为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 共线凸包的更多相关文章

  1. HDU 4946 Area of Mushroom 凸包 第八次多校

    题目链接:hdu 4946 题意:一大神有N个学生,各个都是小神,大神有个二次元空间,每一个小神都有一个初始坐标,如今大神把这些空间分给徒弟们,规则是假设这个地方有一个人比谁都先到这,那么这个地方就是 ...

  2. HDU 4946 凸包

    给你n个点,具有速度,一个位置如果有其他点能够先到,则不能继续访问,求出里面这些点哪些点是能够无限移动的. 首先我们考虑到,一个速度小的和一个速度大的,速度小的必定只有固定他周围的一定区域是它先到的, ...

  3. HDU 5928 DP 凸包graham

    给出点集,和不大于L长的绳子,问能包裹住的最多点数. 考虑每个点都作为左下角的起点跑一遍极角序求凸包,求的过程中用DP记录当前以j为当前末端为结束的的最小长度,其中一维作为背包的是凸包内侧点的数量.也 ...

  4. HDU 4946 Area of Mushroom 共线凸包

    题意是在二维平面上 给定n个人 每一个人的坐标和移动速度v 若对于某个点,仅仅有 x 能最先到达(即没有人能比x先到这个点或者同一时候到这个点) 则这个点称作被x占有 若有人能占有无穷大的面积 则输出 ...

  5. hdu 4946 Area of Mushroom(凸包)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=4946 Area of Mushroom Time Limit: 2000/1000 MS (Java/Ot ...

  6. HDU 4946 Area of Mushroom(构造凸包)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4946 题目大意:在一个平面上有n个点p1,p2,p3,p4....pn,每个点可以以v的速度在平面上移 ...

  7. HDU 4946 Area of Mushroom 凸包

    链接:pid=4946">http://acm.hdu.edu.cn/showproblem.php?pid=4946 题意:有n个人.在位置(xi,yi),速度是vi,假设对于某个点 ...

  8. hdu 4946 凸包注意重点

    http://acm.hdu.edu.cn/showproblem.php?pid=4946 给你n个点的坐标和速度,如果一个点能够到达无穷远处,且花费的时间是最少的,则此点输出1,否则输出0. 每个 ...

  9. hdu 4946 Area of Mushroom (凸包,去重点,水平排序,留共线点)

    题意: 在二维平面上,给定n个人 每个人的坐标和移动速度v 若对于某个点,只有 x 能最先到达(即没有人能比x先到这个点或者同时到这个点) 则这个点称作被x占有,若有人能占有无穷大的面积 则输出1 , ...

随机推荐

  1. Notes of the scrum meeting(11/1)

    meeting time:9:00~10:30p.m.,November 1st,2013 meeting place:20号公寓楼前 attendees: 顾育豪                   ...

  2. WinForm中Component Class、User Control及Custom Control的区别和使用建议

    reference: http://blog.csdn.net/redstonehe/article/details/1536549 .NET Framework 为您提供了开发和实现新控件的能力.除 ...

  3. Codeforces Round #311 (Div. 2) D. Vitaly and Cycle 奇环

    题目链接: 点这里 题目 D. Vitaly and Cycle time limit per test1 second memory limit per test256 megabytes inpu ...

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

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

  5. isEmpty()与equals()、==“”区别

    isEmpty方法源码:public static boolean isEmpty(String str) { return (str == null) || (str.length() == 0); ...

  6. Java学习第四篇:数组,排序,查找

    一.数组 1.一维数组 (1).数组的定义 数据类型 数组名[]=new 数据类型[大小] public class Demo1 { public static void main(String[] ...

  7. POJ 1844

    #include <iostream> #define MAXN 20 using namespace std; int value[MAXN]; int place[MAXN]; ]; ...

  8. POJ 4044 Score Sequence

    题目链接 题意 :给你两个序列,进行降序排序,找出连续的公共子序列,将这个子序列输出,然后对个位数升序排序,如果个位数相同就按数的大小排,再输出这个新排好的. 思路 :先排序,再找公共子序列,最后个位 ...

  9. 通过快捷键及cmd命令注销系统

    公司的外网内网是隔离的 外网的远程电脑屏幕一半卡那了,页面注销键正好在卡死的那一半屏幕上,用以下简单方法注销远程重新连接,问题解决了. 1.通过快捷键win+r打开“运行...” 2.输入CMD 回车 ...

  10. jmeter 使用聚合报告分析jtl文件

    对于jmeter测试生成产生的jtl文件除了使用jemter插件来产生csv或者结果,还可以直接用聚合报告来打开,下面来介绍一下怎么操作. 1. 产生jtl文件 注意,默认情况下聚合报告插件只能分析聚 ...