- 转化为 2D 求点是否在凸包内的问题。一个包装规格定义一个 2 维平面的向量(S2 - S1,S3 - S1),所求的就是这些向量组成的多边形是否包含原点(0,0),如果包含原点,则有非负整数解,否则无非负整数解。如果无解,向量都严格在经过原点的某条直/线的半平面内。可以采用判断两个相邻向量之间的夹角,如果任意两个向量的夹角都不超过PI 弧度,则方程有解,否则无解。考虑有 n 个向量 V1 - Vn,按向量与 X 轴成角的大小从小到大排列,若相邻向量的夹角在 PI弧度以内,则可以将多余的向量去掉,留下三个向量,设为 W1,W2,W3,则一定有某个向量处于两外两个向量的中间,假设为 W2 处于W1 和 W3 中间,则可以找到适当的非负系数使得 x * W1 + y * W3 的和与 -W3 相等。系数是有理数,可以乘以相应的数使得 x 和 y 变成整数。
注意解题过程中应选择 long long 型整数以避免溢出。使用set,复杂度O(nlogn),time:0ms#include <iostream> #include <cstdio> #include <cstring> #include <set> using namespace std; struct node{ long long x,y; //****************** bool operator<(node u) const{ if (y*u.y<=0){//*********long long if (y==0 && u.y==0) return x<u.x; else return y<u.y; } else return (x*u.y-u.x*y)>0; //************************** } }; long long cross(node a,node b){ return a.x*b.y-b.x*a.y; } long long dot(node a,node b){ return a.x*b.x+a.y*b.y; } set<node> s; node p[1010]; int main() { int n,x,y,z,i,flag; node t,u,v; set<node>::iterator l,r,now; while(scanf("%d",&n)!=-1){ if (n==0) break; s.clear(); for (i=1;i<=n;i++){ scanf("%d %d %d",&x,&y,&z); p[i].x=y-x;p[i].y=z-x; s.insert(p[i]); //cout<<s.size()<<endl; } flag=0; //cout<<s.size()<<endl; if (s.size()==2){ //***************************Set may degenerate! //for (set<node>::iterator j=s.begin();j!=s.end();j++) cout<<(*j).x<<' '<<(*j).y<<endl; u=*(s.begin());r=s.end();r--;v=(*r); if (cross(v,u)==0 && dot(v,u)<0) flag=1; } for (i=1;s.size()>2 && i<=n;i++){ t=p[i]; s.erase(p[i]); p[i].x=-p[i].x;p[i].y=-p[i].y; now=s.lower_bound(p[i]); if (now==s.begin()) { l=now; r=s.end(); } else { if (now==s.end()){ now--;r=now;l=s.begin(); } else { l=now;r=now;--r; } } u=*l;v=*r; if (cross(p[i],u)==0 && dot(p[i],u)>0) flag=1; if (cross(p[i],v)==0 && dot(p[i],v)>0) flag=1; if (cross(v,u)>0 && cross(v,p[i])>0 && cross(p[i],u)>0) flag=1; s.insert(t); if (flag) break; } if (flag) printf("Yes\n"); else printf("No\n"); } return 0; }
UVA 10089 Repackaging
最新推荐文章于 2018-02-23 17:51:55 发布