分析
遇到新的题,要思考着往学过的模型上套
这道题要求的是水平可见直线,其实稍微转化一下,就会发现最后能够被看见的直线恰好形成了一个开口向上的半凸包的样子
我们画出一个半凸包,可以发现每条边的斜率是在从左往右依次增加,而其交点横坐标的大小也在递增
可以利用这个性质,对这道题进行求解
将直线按斜率从小到大的顺序排序,依次加入栈中,当当前直线与栈顶直线的交点位于栈中前两条直线交点的左边时,说明栈顶直线会被新加入的直线所挡住,弹出栈顶元素
这样一直做下去,最后留在栈中的直线就是可见的
最后。别忘了判重,思考极端数据:
有毒吧……建议大家到洛谷上去交这道题,BZOJ的数据水啊
代码
#include<bits/stdc++.h>
#define N 500009
#define in read()
#define eps 1e-8
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return f==1?res:-res;
}
struct point {
double x,y;
};
struct Line{
double k,b;
int id;
}line[N];
int n;
double a,b;
bool cmp(const Line &a,const Line &b){
if(fabs(a.k-b.k)<eps) return a.b<b.b;
return a.k<b.k;
}
bool cmp2(const Line &a,const Line &b)
{
return a.id<b.id;
}
Line s[N];
double ask(Line a,Line b){
return (b.b-a.b)/(a.k-b.k);
}
int main(){
n=in;
int i,j;
for(i=1;i<=n;++i)
{
scanf("%lf%lf",&a,&b);
line[i].k=a;line[i].b=b;
line[i].id=i;
}
if(n==1) {printf("1 ");return 0;}
if(n==2) {
int num=(line[2].b-line[1].b>eps)?2:1;
if(fabs(line[1].k-line[2].k)<eps) printf("%d ",num);
else printf("1 2 ");
return 0;
}
sort(line+1,line+n+1,cmp);
double inter;
int qn=0;
s[++qn]=line[1];
for(i=2;i<=n;++i){
if(fabs(line[i].k-s[qn].k)<eps) qn--;
while(qn>1&&ask(line[i],s[qn] )<=ask(s[qn],s[qn-1])) qn--;
s[++qn]=line[i];
}
sort(s+1,s+qn+1,cmp2);
for(i=1;i<=qn;++i) printf("%d ",s[i].id);
return 0;
}
最后一点WA的代码
#include<bits/stdc++.h>
#define N 500009
#define in read()
#define eps 1e-8
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return f==1?res:-res;
}
struct point {
double x,y;
};
struct Line{
double k,b;
int id;
}line[N];
int n;
double a,b;
bool cmp(const Line &a,const Line &b){
if(fabs(a.k-b.k)<eps) return a.b<b.b;
return a.k<b.k;
}
bool cmp2(const Line &a,const Line &b)
{
return a.id<b.id;
}
Line s[N];
double ask(Line a,Line b){
return (b.b-a.b)/(a.k-b.k);
}
int main(){
n=in;
int i,j;
for(i=1;i<=n;++i)
{
scanf("%lf%lf",&a,&b);
line[i].k=a;line[i].b=b;
line[i].id=i;
}
if(n==1) {printf("1 ");return 0;}
if(n==2) {
int num=(line[2].b-line[1].b>eps)?2:1;
if(fabs(line[1].k-line[2].k)<eps) printf("%d ",num);
else printf("1 2 ");
return 0;
}
sort(line+1,line+n+1,cmp);
double inter;
int qn=0;
s[++qn]=line[1];s[++qn]=line[2];
for(i=3;i<=n;++i){
if(fabs(line[i].k-s[qn].k)<eps) qn--;//如果第一条边不合法,则不会被弹掉,改为while即可
while(qn>1&&ask(line[i],s[qn] )<=ask(s[qn],s[qn-1])) qn--;
s[++qn]=line[i];
}
sort(s+1,s+qn+1,cmp2);
for(i=1;i<=qn;++i) printf("%d ",s[i].id);
return 0;
}