题目链接
http://poj.org/problem?id=2653
题意
在
一
个
二
维
平
面
上
依
次
放
置
n
条
木
棍
,
问
最
后
没
有
被
覆
盖
的
木
棍
有
哪
些
,
n
<
=
1
e
5
,
答
案
<
=
1000
在一个二维平面上依次放置n条木棍,问最后没有被覆盖的木棍有哪些,n<=1e5,答案<=1000
在一个二维平面上依次放置n条木棍,问最后没有被覆盖的木棍有哪些,n<=1e5,答案<=1000
做法
我
们
时
光
倒
流
一
下
,
从
后
往
前
做
这
道
题
我们时光倒流一下,从后往前做这道题
我们时光倒流一下,从后往前做这道题
很
明
显
最
后
一
根
木
棍
一
定
是
在
最
上
面
的
,
那
么
这
条
木
棍
所
覆
盖
的
木
棍
一
定
都
是
被
覆
盖
的
很明显最后一根木棍一定是在最上面的,那么这条木棍所覆盖的木棍一定都是被覆盖的
很明显最后一根木棍一定是在最上面的,那么这条木棍所覆盖的木棍一定都是被覆盖的
依
次
递
推
就
能
求
出
所
有
被
最
后
一
条
木
棍
直
接
覆
盖
或
者
间
接
覆
盖
的
木
棍
依次递推就能求出所有被最后一条木棍直接覆盖或者间接覆盖的木棍
依次递推就能求出所有被最后一条木棍直接覆盖或者间接覆盖的木棍
然
后
继
续
向
前
扫
描
到
一
个
没
有
被
覆
盖
的
木
棍
,
然
后
重
复
这
个
过
程
然后继续向前扫描到一个没有被覆盖的木棍,然后重复这个过程
然后继续向前扫描到一个没有被覆盖的木棍,然后重复这个过程
这
样
就
可
以
得
到
所
有
在
最
顶
层
的
木
棍
,
如
果
我
们
用
v
i
s
标
记
被
覆
盖
木
棍
的
方
法
这样就可以得到所有在最顶层的木棍,如果我们用vis标记被覆盖木棍的方法
这样就可以得到所有在最顶层的木棍,如果我们用vis标记被覆盖木棍的方法
时
间
复
杂
度
为
n
2
时间复杂度为n^2
时间复杂度为n2
但
是
如
果
我
们
用
l
i
s
t
里
面
的
l
i
s
t
维
护
没
有
被
覆
盖
的
木
棍
,
时
间
复
杂
度
就
是
O
(
n
∗
1000
)
。
但是如果我们用list里面的list维护没有被覆盖的木棍,时间复杂度就是O(n*1000)。
但是如果我们用list里面的list维护没有被覆盖的木棍,时间复杂度就是O(n∗1000)。
代码
#include<stdio.h>
#include<math.h>
#include<queue>
#include<list>
#include<iostream>
#include<algorithm>
using namespace std;
const double eps = 1e-12;
const double pi = acos(-1.0);
const int maxp = 1010;
int sgn( double x)
{
if (fabs(x) <eps) return 0;
if(x <0) return -1;
return 1;
}
struct Point
{
double x, y;
Point() {}
Point ( double _x, double _y)
{
x = _x, y = _y;
}
bool operator == (Point b) const
{
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator < (Point b) const
{
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator - (const Point &b) const
{
return Point(x - b.x, y - b.y);
}
//叉积 |a||b|sin
double operator ^ (const Point &b) const
{
return x * b.y - y * b.x;
}
//点积 |a||b|cos 向量点积之后反过来求夹角
double operator * (const Point & b) const
{
return x * b.x + y * b.y;
}
Point operator + (const Point &b) const
{
return Point(x + b.x, y + b.y);
}
};
struct Line
{
Point s, e;
Line() {}
Line(Point _s, Point _e)
{
s = _s, e = _e;
}
//两线段相交判断
//2 规范相交
//1 非规范相交-过端点
//0 不相交
int segcrossseg(Line v)
{
int d1 = sgn((e-s)^(v.s-s));
int d2 = sgn((e-s)^(v.e-s));
int d3 = sgn((v.e-v.s)^(s-v.s));
int d4 = sgn((v.e-v.s)^(e-v.s));
if((d1^d2)==-2&&(d3^d4)==-2) return 2;
return ((d1==0&&sgn((v.s-s)*(v.s-e))<=0)||(d2==0&&sgn((v.e-s)*(v.e-e))<=0)||(d3==0&&sgn((s-v.s)*(s-v.e))<=0)||(d4==0&&sgn((e-v.s)*(e-v.e))<=0));
}
};
const int maxn = 1e5+10;
Line l[maxn];
vector<int>ans;
list<int> L;
void del(list<int>::iterator it)//递归算出所有被当前线段所影响的线段
{
Line now = l[*it];
list<int>::iterator tmp=it;
for(list<int>::iterator itt=(++it);itt!=L.end();)
{
Line nex = l[*itt];
if(now.segcrossseg(nex))
{
del(itt);//找到之后先递归,再将本点删除
itt=L.erase(itt);
}
else ++itt;
}
return ;
}
int main()
{
int n;
double xa,xb,ya,yb;
while(scanf("%d",&n)!=EOF)
{
L.clear();
ans.clear();
if(n==0) break;
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&xa,&ya,&xb,&yb);
l[i]=Line (Point(xa,ya),Point(xb,yb));
}
for(int i=n;i>=1;i--)
{
L.push_back(i);
}
for(list<int>::iterator it=L.begin();it!=L.end();)
{
list<int>::iterator tmp=it;
del(it);
it=++tmp;//由于有删除操作,要先存当前指针位置,在删除之后让迭代器指向当前的下一位
}
L.reverse();
for(list<int>::iterator it=L.begin();it!=L.end();++it)
{
int tmp=*it;
ans.push_back(tmp);
}
sort(ans.begin(),ans.end());//保证答案有序
printf("Top sticks:");
for(int i=0;i<ans.size();i++)
{
if(i!=ans.size()-1) printf(" %d,",ans[i]);
else printf(" %d.\n",ans[i]);
}
}
return 0;
}