P3194 [HNOI2008] 水平可见直线
题解
想象一下,从左上角无限大的地方开始,第一个看到的一定是斜率最小的且截距最大的,慢慢往右下角滑,第一个碰到的直线一定是斜率比前一个小(不一定是第二小)的但是是它的斜率所属直线里截距最大的
重复上述步骤,最外面的直线一定长这样

图片来自luogu,linaonao
所以我们可以按斜率排序所有直线,斜率相同的直线按截距排序
如果出现一条直线斜率大但是截距也大,那么它可能会盖过前边斜率小的直线,所以有点像单调栈,因为它会一直盖直到盖不住,这样那些被盖住的直线就被弹出去了
感觉讲的还不是很清晰,水平还不够
code
#include<bits/stdc++.h>
using namespace std;
struct node
{
double a,b;
int id;
}line[500005];
int q[500005];
bool cmp(node x,node y)
{
if(x.a!=y.a) return x.a<y.a;
return x.b>y.b;
}
bool cmp2(int i,int j)
{
return line[i].id<line[j].id;
}
double cal(int i,int j)
{
node x=line[i],y=line[j];
return 1.0*(y.b-x.b)/(x.a-y.a);
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>line[i].a>>line[i].b;
line[i].id=i;
}
sort(line+1,line+1+n,cmp);
q[1]=1;
int top=1;
for(int i=2;i<=n;i++)
{
if(line[i].a==line[q[top]].a) continue;
while(top>1&&cal(i,q[top-1])<=cal(q[top],q[top-1]))top--;
q[++top]=i;
}
sort(q+1,q+1+top,cmp2);
for(int i=1;i<=top;i++) cout<<line[q[i]].id<<" ";
return 0;
}

浙公网安备 33010602011771号