题意:给定一条折线,问能否在不扭曲它的情况下让它完全通过一个小孔
这个条件就是:过折线上任意一点$x$存在一条直线把折线分成不与直线相交的两部分,换句话说存在(与折线只有一个交点$x$)的直线
结论是:若点$i$严格在点$1\cdots i$或点$i\cdots n$构成的凸包内,则无解,因为过点$i$的直线必然与折线在其他的某些位置相交
所以我们可以用set维护仅插入动态凸包,边插入边查询即可
实际上没有必要维护整个凸包,只维护原来的点还有它关于原点对称点的上凸壳就可以了
注意C++做布尔运算的短路机制==
#include<stdio.h> #include<set> using namespace std; typedef long long ll; struct point{ int x,y; point(int a=0,int b=0){x=a;y=b;} }p[100010]; point operator-(point a,point b){return point(a.x-b.x,a.y-b.y);} ll operator*(point a,point b){return(ll)a.x*b.y-(ll)a.y*b.x;} struct cmp{ bool operator()(point a,point b){return a.x==b.x?a.y<b.y:a.x<b.x;} }; struct conv{ typedef set<point,cmp> st; typedef st::iterator si; st s; si it; si pre(si i){ i--; return i; } si nex(si i){ i++; return i; } point d[100010]; int M,siz; void clear(){s.clear();siz=0;} bool insert(point p){ it=s.lower_bound(p); if(it!=s.begin()&&it!=s.end()&&(p-*pre(it))*(*it-p)>=0)return 0; M=0; if(it!=s.begin()){ it--; while(it!=s.begin()&&(*it-*pre(it))*(p-*it)>=0)d[++M]=*(it--); } it=s.lower_bound(p); if(it!=s.end()){ while(nex(it)!=s.end()&&(*it-p)*(*nex(it)-*it)>=0)d[++M]=*(it++); } while(M)s.erase(d[M--]); s.insert(p); siz=s.size(); return 1; } }c1,c2; int n; void work(){ int i; bool f1,f2; for(i=1;i<=n;i++)scanf("%d%d",&p[i].x,&p[i].y); c1.clear(); c2.clear(); for(i=1;i<=n;i++){ f1=!c1.insert(p[i]); f2=!c2.insert(0-p[i]); if(f1&&f2){ puts("Impossible"); return; } } c1.clear(); c2.clear(); for(i=n;i>0;i--){ f1=!c1.insert(p[i]); f2=!c2.insert(0-p[i]); if(f1&&f2){ puts("Impossible"); return; } } puts("Possible"); } int main(){ while(~scanf("%d",&n))work(); }