HYSBZ/BZOJ 1007 [HNOI2008] 水平可见直线 - 计算几何
分析:
直角坐标系内,有n条直线分布,求:最大值(对于任意x,直线上能取到的max( f(x) ))构成的折线由哪些直线构成。
Solution :
把直线按照斜率从小到大排序。
从左到右:先找到中斜率最小的直线 r ,它一定属于ans的集合,找到这条直线与所有直线中横坐标最小的点(x0,y0),由x0确定下一条直线 tar(由于可能出现几条直线交 r 于同一点的情况,取这些直线中斜率最大的。)
根据这样的步骤循环找ans,直到当前直线 r 没有与其他直线的交点了为止。
O(
因为排了序,而且直线的斜率必须由小到大,所以,当当前直线 r 找交点的时候,可以不用考虑斜率小于这条直线的线了,由于当前找到的直线是不确定,所以只有时间上限 O(
代码不好看啊,当时写的时候分了斜率大于0小于0两部分,其实没必要。
推荐一个blogby Liu Junhao
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAXN 50000
#define MAXM 500000
#define INF 2147483646
const double eps=1e-30;
struct node{
int a,b,id;
}s[MAXN+10],t[MAXN+10];
int n,cnts,cntt,c[MAXM*2+10][2],d[MAXM*2+10][2];
bool ans[MAXN+10];
bool cmp(node x,node y){
if(x.a==y.a) return x.b>y.b;
return x.a<y.a;
}
void read()
{
int x,y;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&x,&y);
if(x<0){
if(c[x+MAXM][1]){
if(c[x+MAXM][0]<y)
c[x+MAXM][0]=y,c[x+MAXM][1]=i;
}
else
c[x+MAXM][0]=y,c[x+MAXM][1]=i;
}
else{
if(d[x+MAXM][1]){
if(d[x+MAXM][0]<y)
d[x+MAXM][0]=y,d[x+MAXM][1]=i;
}
else
d[x+MAXM][0]=y,d[x+MAXM][1]=i;
}
}
//去掉斜率相同的直线不仅可以优化一小下下,最重要的是避免后面算交点的时候出错(出现除数为0)
for(int i=0;i<=MAXM*2;i++){
if(c[i][1]){
s[++cnts].a=i-MAXM,s[cnts].b=c[i][0];
s[cnts].id=c[i][1];
}
if(d[i][1]){
t[++cntt].a=i-MAXM,t[cntt].b=d[i][0];
t[cntt].id=d[i][1];
}
}
}
int main()
{
read();
sort(s+1,s+cnts+1,cmp);
sort(t+1,t+cntt+1,cmp);
int r,p,q;
bool last;
if(cnts){
r=1,p=2,q=1,last=false;
ans[s[r].id]=true;
}
else{
r=1,p=1,q=2,last=true;
ans[t[r].id]=true;
}
double X=-INF;
while(true){
int tar=-1;
double x0=INF,tmp;
bool flag=false;
for(int k=p;k<=cnts;k++){
tmp=1.0*(s[k].b-s[r].b)/(s[r].a-s[k].a);
if(tmp>=X&&tmp<=x0){
if(fabs(tmp-x0)<=eps){
if(tar!=-1&&s[k].a<s[tar].a)
continue;
}
tar=k;
x0=tmp;
}
}
for(int k=q;k<=cntt;k++){
if(last)
tmp=1.0*(t[k].b-t[r].b)/(t[r].a-t[k].a);
else
tmp=1.0*(t[k].b-s[r].b)/(s[r].a-t[k].a);
if(tmp>=X&&tmp<=x0){
if(fabs(tmp-x0)<=eps){
if(tar!=-1&&t[k].a<t[tar].a)
continue;
}
tar=k;
flag=true;
x0=tmp;
}
}
if(tar==-1)
break;
if(!flag){
if(x0==X) ans[s[r].id]=false;
else X=x0;
ans[s[tar].id]=true,r=tar;
p=tar+1;
}
else{
if(x0==X){
if(!last) ans[s[r].id]=false;
else ans[t[r].id]=false;
}
else X=x0;
ans[t[tar].id]=true,r=tar;
p=cnts+1,q=tar+1;
}
last=flag;
}
for(int i=1;i<=n;i++)
if(ans[i])
printf("%d ",i);
}