题意
在一个圆上有 n n n 条线段,若有交点,输出 Y e s Yes Yes,否则输出 N o No No。
思路
我们可以使用栈。将每条线段的起点和终点标记为相同的标记。
例: p i p_i pi 代表第 i i i 个点的编号。
线段 1 1 1 的端点为 1 1 1 和 5 5 5 ,将 p 1 p_1 p1 和 p 5 p_5 p5 标记为 1 1 1。
线段 2 2 2 的端点为 2 2 2 和 4 4 4,将 p 2 p_2 p2 和 p 4 p_4 p4 标记为 2 2 2。
以此类推。
先在栈中投入一个数字,避免一开始栈是空的,我们可以往里面放一个负数,如
−
114
-114
−114。
如果要进的数字等于栈首并且栈不是空的,我们把栈首弹出,否则将数字压进栈里。
最后,如果栈最后剩下一个(就是一开始我们放进那一个 − 114 -114 −114)那么没有交点,输出 N o No No,否则输出 Y e s Yes Yes。
那么,为什么最后只剩下一个就是没有交点呢?
我们可以想到,如果两条线段交叉,那么他们的端点必然是交替出现的。
没有交替出现。
交替出现。
重点来了!!!
我们把端点依次放入栈中,如果端点编号与栈首相同,那么就出栈,否则就入栈。若栈空,那么就说明端点没有交替出现,线段没有交点。(可以自己根据图一和图二模拟一下,得到的结果就是上述的)
图二模拟
2 |
---|
1 |
2 |
1 |
在题目中是这样
2 |
---|
1 |
2 |
1 |
-114 |
图一模拟
略
代码
#include<iostream>
#include<stack>
using namespace std;
#define int long long
const int N=2e5+3;
struct id{
int x,y;
}a[2*N];
stack<int> st;
int p[2*N];//p数组存编号
signed main(){
int n;
cin>>n;
int X,Y;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y;
if(a[i].x>a[i].y) swap(a[i].x,a[i].y);//此句可以不加
}
for(int i=1;i<=n;i++){
p[a[i].x]=p[a[i].y]=i;
}
st.push(-114);
for(int i=1;i<=2*n;i++){
int d=p[i];
if(d==st.top()&&!st.empty( )){
st.pop();
}
else{
st.push(d);
}
}
//cout<<st.size()<<endl;
if(st.size( )==1) cout<<"No";
else cout<<"Yes";
return 0;
}