@y20070316
2017-03-01T08:40:45.000000Z
字数 23684
阅读 1020
OI
bzoj2618√
bzoj3190√
bzoj2732
bzoj1038
bzoj1007√
bzoj1137√
bzoj3800
按照【bzoj1007】那种用斜率求小于180°的半平面交的方法。
然后把交点的x小于0的部分全都除掉。
注意特判两条线重合的情况。
规则:
①如果露出一个点,那么也要算。
②如果重合,那么也要算。
对此,我们对斜率排序后,保留重合且截距最大的,还有斜率不同的。
判断删除某个半平面的时候,用而不是,确定出。
确定的时候,还要避免重合的情况,往后移,然后再往左移。
#include <cstdio>#include <cctype>#include <cmath>#include <algorithm>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)#define LD long doubleconst int N=16384;int n;struct Line {int id; LD k,b;Line(int _id=0,LD _k=0,LD _b=0):id(_id),k(_k),b(_b){}friend int operator < (Line a,Line b) {if (a.k!=b.k) return a.k<b.k; else return a.b>b.b;}}p[N];int ID(Line a,Line b) {return a.id<b.id;}Line s[N];int l,r;int rd(void) {int x=0,f=1; char c=getchar();for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;for (;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}LD inter(Line a,Line b) {return -(a.b-b.b)/(a.k-b.k);}int main(void) {#ifndef ONLINE_JUDGEfreopen("sdchr.in","r",stdin);freopen("sdchr.out","w",stdout);#endifn=rd(); F(i,1,n) p[i].id=i; F(i,1,n) p[i].b=rd(); F(i,1,n) p[i].k=rd();sort(p+1,p+n+1);int t=0;F(i,1,n) {Line tmp=p[i];int j=i;while (j+1<=n&&p[j+1].k==p[i].k)j++;F(k,i,j)if (p[k].b==tmp.b)p[++t]=p[k];i=j;}n=t;F(i,1,n) {while (r>=2) {LD x1=inter(p[i],s[r-1]);LD x2=inter(p[i],s[r]);if (x1>x2)s[r--]=Line();else break;}s[++r]=p[i];}t=l=1;while (t+1<=r)if ((s[t].b==s[t+1].b&&s[t].k==s[t+1].k)||inter(s[t],s[t+1])<0)t++;else break;while (t-1>=l)if (s[t].b==s[t-1].b&&s[t].k==s[t-1].k)t--;else break;l=t;printf("%d\n",r-l+1);sort(s+l,s+r+1,ID);F(i,l,r-1)printf("%d ",s[i].id);printf("%d\n",s[r].id);return 0;}
#include <cstdio>#include <cctype>#include <cmath>#include <algorithm>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)#define Vector pointconst int M=64;const int L=512;int m;struct point {double x,y;point(double _x=0,double _y=0):x(_x),y(_y){}friend point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);}friend point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}point operator * (double w) {return point(x*w,y*w);}friend double operator ^ (point a,point b) {return a.x*b.y-a.y*b.x;}}p[M];int n,tot;struct Line {point x;Vector v;double ang;Line(point _x=point(),Vector _v=point()):x(_x),v(_v){}friend int operator < (Line a,Line b) {if (a.ang!=b.ang)return a.ang<b.ang;else return (a.v^(b.x-a.x))<0;}void Ang(void) {ang=atan2(v.y,v.x);}}line[L];Line s[L];int l,r;point it[L];int len;double ans;int rd(void) {int x=0,f=1; char c=getchar();for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;for (;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}point Inter(Line a,Line b) {Vector u=a.x-b.x;double t=(u^b.v)/(b.v^a.v);return a.x+a.v*t;}int on_right(Line a,point p) {return (a.v^(p-a.x))<=0;}void HPI(void) {sort(line+1,line+tot+1);int t=0;F(i,1,tot)if (line[i].ang!=line[i-1].ang)line[++t]=line[i];tot=t;l=1,r=0;F(i,1,tot) {while (l<r&&on_right(line[i],Inter(s[r-1],s[r])))s[r--]=Line();while (l<r&&on_right(line[i],Inter(s[l],s[l+1])))s[l++]=Line();s[++r]=line[i];}while (l<r&&on_right(s[l],Inter(s[r-1],s[r])))s[r--]=Line();s[r+1]=s[l];}int main(void) {#ifndef ONLINE_JUDGEfreopen("sdchr.in","r",stdin);#endifn=rd();F(j,1,n) {m=rd();F(i,1,m) {double x=rd(),y=rd();p[i]=point(x,y);}p[m+1]=p[1];F(i,1,m)line[++tot]=Line(p[i],p[i+1]-p[i]);}F(i,1,tot) line[i].Ang();HPI();F(i,l,r)it[++len]=Inter(s[i],s[i+1]);F(i,2,len-1)ans+=fabs(((it[i]-it[1])^(it[i+1]-it[1])))/2.0;printf("%0.3lf\n",ans);return 0;}
给定若干条直线。
求从无限高的地方看下来,能看见哪些直线。
需要明确这样几个概念:
半平面:一条直线的一侧的所有区域。通过一条有向的直线来刻画,该线段的上方就是半平面,半平面的斜率就是有向线段的斜率。
半平面交:若干个半平面的交集,就是半平面交。
先说明一下这道题与半平面交的关系。
想象一下,从无线高的地方看下来,你会看到一个下凸壳。
这道题相当于求所有朝向为轴正方向的直线的半平面交。
我们考虑按照直线的斜率进行从小到大的排序,逐个添加,维护半平面交。
如上图所示,其中为蓝线与黑线的交点,为蓝线与棕线的交点。
假设当前我们添加了黑线、棕线,现在要添加蓝线。蓝线有三种可能,分别对应图中的三条蓝线。由此可得:当时,我们直接添加蓝线,否则将棕线进行删除。
#include <bits/stdc++.h>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)#define D(i,a,b) for (int i=(a);i>=(b);i--)#define fore(v,u) for (vector<int>::iterator v=g[u].begin();v!=g[u].end();v++)#define LL long long#define LD long doubleLL rd(void) {LL x=0,f=1; char c=getchar();for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;for (;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}char rdc(void) {char c=getchar();while (!isalpha(c))c=getchar();return c;}const int N=65536;int n;struct Line {int id; double k,b;Line(int _id=0,double _k=0,double _b=0):id(_id),k(_k),b(_b){}friend int operator < (Line a,Line b) {if (a.k!=b.k) return a.k<b.k; else return a.b>b.b;}}line[N];void Init(void) {n=rd();F(i,1,n) {double k=rd(),b=rd();line[i]=Line(i,k,b);}}Line s[N]; int tot;double Cross(Line a,Line b) {//保证a.k!=b.k,返回交点的x坐标return (a.b-b.b)/(a.k-b.k);}int cmp_id(Line a,Line b) {return a.id<b.id;}void Solve(void) {sort(line+1,line+n+1);F(i,1,n) {if (i!=1&&line[i].k==line[i-1].k)continue;while (tot>=2) {double s1=Cross(s[tot],line[i]);double s2=Cross(s[tot-1],line[i]);if (s1>=s2)s[tot--]=Line();else break;}s[++tot]=line[i];}sort(s+1,s+tot+1,cmp_id); F(i,1,tot) printf("%d ",s[i].id); printf("\n");}int main(void) {#ifndef ONLINE_JUDGEfreopen("sdchr.in","r",stdin);#endifInit();Solve();return 0;}
bzoj3533√
bzoj1027√
bzoj2961√
bzoj2300√
bzoj1185√
zoj1081√
hdu2108√
bzoj3203√
bzoj1069√
维护一个向量集合,在线支持以下操作:
"":加入向量;
",,其中为已经加入的向量个数)
询问第个到第个加入的向量与向量的点积的最大值。 集合初始时为空。
首先有这样一个结论:点积最大的向量一定在凸包上。
直观的理解:点积,对于相同的,则要求在上的投影尽可能地大。即要求在的方向上走得越远越好,所以必须要在边界上。
证明:对于点,点积为
确定在凸包上了,我们又有了新发现:凸包上的点按照极角序排序,与的点积是单峰的。所以我们假如能求得凸包,那么在凸包上三分即可解决问题。
至于区间的凸包怎么求。假如能将区间划分成多个子区间,对于每个子区间求凸包进行三分,再取最大值,那么最终求出来的答案亦满足要求。所以考虑使用线段树,每个区间存区间的所有点的凸包。
确定使用线段树的结构后,考虑怎样构建凸包。最简单的想法是维护一个set,动态维护凸包。但是太麻烦了,由于我们每次在序列末插入一个点,所以考虑如果对于某个区间,插入的是这个区间的最后一个点,再把整个区间的点建立凸包。
我写的是zkw线段树,稍微会快一些,然后也是因为中大的那些评委们也会卡常的。
#include <bits/stdc++.h>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)#define D(i,a,b) for (int i=(a);i>=(b);i--)#define fore(v,u) for (vector<int>::iterator v=g[u].begin();v!=g[u].end();v++)#define LL long long#define LD long doubleconst LL MAX=(LL)1e17;const LL MIN=(LL)-1e17;LL rd(void) {LL x=0,f=1; char c=getchar();for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;for (;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}char rdc(void) {char c=getchar();while (!isalpha(c))c=getchar();return c;}int decode(int x,LL ans) {return x^(ans&0x7fffffff);}struct point {int x,y;point(int _x=0,int _y=0):x(_x),y(_y){}friend LL operator / (point a,point b) {return (LL)a.x*b.y-(LL)a.y*b.x;}friend LL operator * (point a,point b) {return (LL)a.x*b.x+(LL)a.y*b.y;}friend int operator < (point a,point b) {if (a.x!=b.x) return a.x<b.x; else return a.y<b.y;}friend point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}};const int N=1048576;int n;int m; int r[N];vector<point> pt[N],up[N],dw[N];void Push(int x,int xl,int xr) {r[x]=xr;if (x<(1<<m)) {int mid=(xl+xr)>>1;Push(x<<1,xl,mid);Push(x<<1|1,mid+1,xr);}}void Prework(void) {n=rd();for (m=1;(1<<m)<=n+1;m++);Push(1,0,(1<<m)-1);}void Flow(int x) {static point tmp[N]; int n=0; F(i,1,pt[x].size()) tmp[++n]=pt[x][i-1];sort(tmp+1,tmp+n+1);static point t2[N]; int tot=0;F(i,1,n) {while (tot>=2&&(t2[tot]-t2[tot-1])/(tmp[i]-t2[tot-1])<=0)t2[tot--]=point();t2[++tot]=tmp[i];}dw[x].resize(tot+1); F(i,1,tot) dw[x][i]=t2[i];tot=0;D(i,n,1) {while (tot>=2&&(t2[tot]-t2[tot-1])/(tmp[i]-t2[tot-1])<=0)t2[tot--]=point();t2[++tot]=tmp[i];}up[x].resize(tot+1); F(i,1,tot) up[x][i]=t2[i];}void Insert(int x,point p) {for (int now=x+(1<<m);now>0;now>>=1) {pt[now].push_back(p);if (r[now]==x)Flow(now);}}LL Query(vector<point> &vec,int l,int r,point p) {while (r-l>=3) {int _l=(l+l+r)/3;int _r=(l+r+r)/3;if (p*vec[_l]>p*vec[_r])r=_r;else l=_l;}LL ans=MIN;F(i,l,r)ans=max(ans,p*vec[i]);return ans;}LL Ask(int l,int r,point p) {LL ans=MIN;for (l--,r++,l+=(1<<m),r+=(1<<m);l^r^1;l>>=1,r>>=1) {if (!(l&1)) {if (p.y>=0) ans=max(ans,Query(up[l^1],1,up[l^1].size()-1,p));if (p.y<=0) ans=max(ans,Query(dw[l^1],1,dw[l^1].size()-1,p));}if (r&1) {if (p.y>=0) ans=max(ans,Query(up[r^1],1,up[r^1].size()-1,p));if (p.y<=0) ans=max(ans,Query(dw[r^1],1,dw[r^1].size()-1,p));}}return ans;}void Work(void) {LL ans=0; char c=rdc(); int tot=0;F(cc,1,n) {char kd=rdc();if (kd=='A') {int x=rd(),y=rd();if (c!='E')x=decode(x,ans),y=decode(y,ans);Insert(++tot,point(x,y));}else if (kd=='Q') {int x=rd(),y=rd(),l=rd(),r=rd();if (c!='E')x=decode(x,ans),y=decode(y,ans),l=decode(l,ans),r=decode(r,ans);ans=Ask(l,r,point(x,y));printf("%lld\n",ans);}}}int main(void) {#ifndef ONLINE_JUDGEfreopen("sdchr.in","r",stdin);freopen("sdchr.out","w",stdout);#endifPrework();Work();return 0;}
数形结合+计算几何+Floyd最小环。
http://blog.csdn.net/popoqqq/article/details/40539273
#include <cstdio>#include <climits>#include <cmath>#include <algorithm>using namespace std;#define rep(i,a,b) for (int i=(a);i<=(b);i++)const int M=512;const int N=512;const int MAX=INT_MAX>>1;const double EPS=1e-15;int cmp(double x);int m,n;struct point{double x,y;point(double _x=0,double _y=0) {x=_x,y=_y;}friend point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}friend point operator * (point a,point b) {return point(a.x*b.x,a.y*b.y);}friend int operator == (point a,point b) {return !cmp(a.x-b.x)&&!cmp(a.y-b.y);}friend int operator != (point a,point b) {return !(a==b);}}mer[M],prd[N];int f[M][M];int res;void Init(void) {scanf("%d%d",&m,&n);rep(i,1,m) {double x,y; scanf("%lf%lf%*lf",&x,&y);mer[i]=point(x,y);}rep(i,1,n) {double x,y; scanf("%lf%lf%*lf",&x,&y);prd[i]=point(x,y);}}int cmp(double x){if(fabs(x)<EPS) return 0;return x>0?1:-1;}double det(point a,point b) {return a.x*b.y-a.y*b.x;}int Left(point k,point a,point b) {double t=det(b-a,k-a);return t>0;}int On(point k,point a,point b) {if (cmp(det(k-a,b-a))!=0) return 0;if (!(cmp(min(a.x,b.x)-k.x)<=0&&cmp(k.x-max(a.x,b.x))<=0)) return 0;if (!(cmp(min(a.y,b.y)-k.y)<=0&&cmp(k.y-max(a.y,b.y))<=0)) return 0;return 1;}/*bool On(const point &a,const point &b,const point &c) {return !cmp(det(a-b,c-b))&&cmp((a.x-b.x)*(a.x-c.x))<=0&&cmp((a.y-b.y)*(a.y-c.y))<=0;}*/int Check(point a,point b) {rep(i,1,n) {int t1=Left(prd[i],a,b);int t2=On(prd[i],a,b);if (!t1&&!t2) return 0;}return 1;}void MakeGraph(void) {rep(i,1,m) rep(j,1,m) f[i][j]=MAX;rep(i,1,m) rep(j,1,m)if (Check(mer[i],mer[j]))f[i][j]=1;}int Floyd(void) {rep(i,1,m) {int mrk=1;rep(j,1,n) if (mer[i]!=prd[j]) {mrk=0;break;}if (mrk) return 1;}rep(i,1,m) rep(j,1,m) {int mrk=1;rep(k,1,n)if (!On(prd[k],mer[i],mer[j])) {mrk=0;break;}if (mrk) return 2;}/*rep(i,1,m) {rep(j,1,m)if (f[i][j]!=MAX)printf("%d ",f[i][j]);else printf("0 ");printf("\n");}*/int ans=MAX;rep(k,1,m) rep(i,1,m) rep(j,1,m)f[i][j]=min(f[i][j],f[i][k]+f[k][j]);rep(i,1,m) ans=min(ans,f[i][i]);return ans!=MAX?ans:-1;}int main(void) {#ifndef ONLINE_JUDGEfreopen("bzoj1027.in","r",stdin);freopen("bzoj1027.out","w",stdout);#endifInit();MakeGraph();res=Floyd();printf("%d\n",res);return 0;}
在平面直角坐标系中,Wayne需要你完成次操作,操作只有两种:
:表示在坐标系中加入一个以为圆心且过原点的圆。
:表示询问点是否在所有已加入的圆的内部(含圆周),且至少在一个圆内部(含圆周)。
为了减少你的工作量,题目保证圆心严格在x轴上方(纵坐标为正),且横坐标非零。
数据范围:
我们考虑怎么判定一个点是否在一个以半径为、以为圆心的圆上。
我们有:
#include <bits/stdc++.h>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)#define D(i,a,b) for (int i=(a);i>=(b);i--)#define fore(v,u) for (vector<int>::iterator v=g[u].begin();v!=g[u].end();v++)#define LL long long#define LD doubleLL rd(void) {LL x=0,f=1; char c=getchar();for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;for (;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}char rdc(void) {char c=getchar();while (!isalpha(c))c=getchar();return c;}#define N 524288struct point {LD x,y;point(LD _x=0,LD _y=0):x(_x),y(_y){}friend point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}friend LD operator / (point a,point b) {return a.x*b.y-a.y*b.x;}friend int operator < (point a,point b) {if (a.x!=b.x) return a.x<b.x; else return a.y<b.y;}}org;int m;struct OP {int kd; point p;OP(int _kd=0,point _p=point()):kd(_kd),p(_p){}}op[N];int ans[N],cnt[N];point p[N]; int n;point s_dw[N]; int tot_dw;point s_up[N]; int tot_up;void Graham(void) {sort(p+1,p+n+1);while (tot_dw>0) s_dw[tot_dw--]=point();F(i,1,n) {while (tot_dw>=2&&(s_dw[tot_dw]-s_dw[tot_dw-1])/(p[i]-s_dw[tot_dw-1])<=0)s_dw[tot_dw--]=point();s_dw[++tot_dw]=p[i];}while (tot_up>0) s_up[tot_up--]=point();D(i,n,1) {while (tot_up>=2&&(s_up[tot_up]-s_up[tot_up-1])/(p[i]-s_up[tot_up-1])<=0)s_up[tot_up--]=point();s_up[++tot_up]=p[i];}}#define x0 now.x#define y0 now.y#define A 0.00#define B 100.00int Check(point now) {if (y0==0)return (2*x0*s_dw[1].x>=x0*x0+y0*y0&&2*x0*s_dw[tot_dw].x>=x0*x0+y0*y0);point a(A,(x0*x0+y0*y0-2*x0*A)/(2*y0));point b(B,(x0*x0+y0*y0-2*x0*B)/(2*y0));if (y0>0) {int l=1,r=tot_dw;while (r-l>=3) {int _l=(l+l+r)/3;int _r=(l+r+r)/3;LD ql=(b-a)/(s_dw[_l]-a); if (ql<0) return 0;LD qr=(b-a)/(s_dw[_r]-a); if (qr<0) return 0;if (ql<qr) r=_r; else l=_l;}F(i,l,r) if ((b-a)/(s_dw[i]-a)<0) return 0;}else if (y0<0) {swap(a,b);int l=1,r=tot_up;while (r-l>=3) {int _l=(l+l+r)/3;int _r=(l+r+r)/3;LD ql=(b-a)/(s_up[_l]-a); if (ql<0) return 0;LD qr=(b-a)/(s_up[_r]-a); if (qr<0) return 0;if (ql<qr) r=_r; else l=_l;}F(i,l,r) if ((b-a)/(s_up[i]-a)<0) return 0;}return 1;}void Solve(int l,int r) {if (l==r) return;int mid=(l+r)>>1;if (l<=mid) Solve(l,mid);if (mid+1<=r) Solve(mid+1,r);while (n>0) p[n--]=point(); F(i,l,mid) if (op[i].kd==0) p[++n]=op[i].p; if (!n) return;Graham();F(i,mid+1,r) if (op[i].kd==1) {if (ans[i]) ans[i]=Check(op[i].p);cnt[i]++;}}int main(void) {#ifndef ONLINE_JUDGEfreopen("sdchr.in","r",stdin);#endifm=rd();F(i,1,m) {int kd=rd(); LD x,y; scanf("%lf%lf",&x,&y);op[i]=OP(kd,point(x,y));}F(i,1,m) ans[i]=1;Solve(1,m);F(i,1,m) if (op[i].kd==1&&!cnt[i]) ans[i]=0;F(i,1,m) if (op[i].kd==1) if (ans[i]) printf("Yes\n"); else printf("No\n");return 0;}
#include <bits/stdc++.h>#include <algorithm>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)#define D(i,a,b) for (int i=(a);i>=(b);i--)#define fore(v,u) for (vector<int>::iterator v=g[u].begin();v!=g[u].end();v++)#define LL long long#define LD long doubleLL rd(void) {LL x=0,f=1; char c=getchar();for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;for (;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}char rdc(void) {char c=getchar();while (!isalpha(c))c=getchar();return c;}struct point {double x,y;point(double _x=0,double _y=0):x(_x),y(_y){}friend point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}friend int operator < (point a,point b) {if (a.x!=b.x) return a.x<b.x; else return a.y<b.y;}friend double operator / (point a,point b) {return a.x*b.y-a.y*b.x;}double norm(void) {return sqrt(x*x+y*y);}void Read(void) {x=rd(),y=rd();}};set<point> s;double sum;void Add(point x) {set<point>::iterator r=lower_bound(s.begin(),s.end(),x),l=r,t; l--;if ((x-*l)/(*r-*l)>0) return;sum-=(*r-*l).norm();while (1) {t=r; r++;if (r==s.end()) break;if ((*t-x)/(*r-x)<0) break;sum-=(*r-*t).norm();s.erase(t);}while (1) {if (l==s.begin()) break;t=l; l--;if ((x-*l)/(*t-*l)>0) break;sum-=(*t-*l).norm();s.erase(t);}s.insert(x);l=r=s.find(x);l--,r++;sum+=(*r-x).norm();sum+=(x-*l).norm();}#define M 262144int m; point p[M]; int v[M];int q,op[M][2]; double ans[M];int main(void) {#ifndef ONLINE_JUDGEfreopen("sdchr.in","r",stdin);#endifint n=rd(),x=rd(),y=rd();s.insert(point(0,0));s.insert(point(n,0));s.insert(point(x,y));sum+=(point(0,0)-point(x,y)).norm();sum+=(point(x,y)-point(n,0)).norm();m=rd(); F(i,1,m) p[i].Read();q=rd();F(i,1,q) if (rd()==2) op[i][0]=2; else op[i][0]=1,v[op[i][1]=rd()]=1;F(i,1,m) if (!v[i]) Add(p[i]);D(i,q,1)if (op[i][0]==2) ans[i]=sum; else Add(p[op[i][1]]);F(i,1,q) if (op[i][0]==2) printf("%0.2lf\n",ans[i]);return 0;}
#include <cstdio>#include <cmath>#include <algorithm>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)#define INF 1e30#define EPS 1e-8#define N 65536int n;struct point {double x,y;point(double _x=0,double _y=0) {x=_x,y=_y;}friend point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);}friend point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}point operator * (double val) {return point(x*val,y*val);}void Read(void) {scanf("%lf%lf",&x,&y);}double norm(void) {return sqrt(pow(x,2)+pow(y,2));}}p[N],org;double dot(point a,point b) {return a.x*b.x+a.y*b.y;}double det(point a,point b) {return a.x*b.y-a.y*b.x;}int cmp(point a,point b) {return det(a-org,b-org)>0;}int tot;point s[N];double ans;point t[4];void Graham(void) {F(i,2,n) if (p[i].y<p[1].y||p[i].y==p[1].y&&p[i].x<p[1].x) swap(p[1],p[i]);org=p[1]; sort(p+2,p+n+1,cmp);F(i,1,n) {while (tot>=2&&det(s[tot]-s[tot-1],p[i]-s[tot-1])<=0)s[tot--]=point();s[++tot]=p[i];}s[0]=s[tot];}void Rot(void) {int l=0,r=0,p=0; ans=INF;F(i,1,tot-1) {if (det(s[1]-s[0],s[i]-s[0])>det(s[1]-s[0],s[p]-s[0])-EPS) p=i;if (dot(s[1]-s[0],s[i]-s[0])>dot(s[1]-s[0],s[r]-s[0])-EPS) r=i;if (dot(s[1]-s[0],s[i]-s[0])<dot(s[1]-s[0],s[l]-s[0])+EPS) l=i;}F(i,0,tot-1) {double D=(s[i+1]-s[i]).norm();while (det(s[i+1]-s[i],s[p+1]-s[i])>det(s[i+1]-s[i],s[p]-s[i])-EPS)p=(p+1)%tot;while (dot(s[i+1]-s[i],s[r+1]-s[i])>dot(s[i+1]-s[i],s[r]-s[i])-EPS)r=(r+1)%tot;while (dot(s[i+1]-s[i],s[l+1]-s[i])<dot(s[i+1]-s[i],s[l]-s[i])+EPS)l=(l+1)%tot;double L=dot(s[i+1]-s[i],s[l]-s[i])/D;double R=dot(s[i+1]-s[i],s[r]-s[i])/D;double H=det(s[i+1]-s[i],s[p]-s[i])/D; H=fabs(H);double tmp=(R-L)*H;if (tmp<ans) {ans=tmp;t[0]=s[i]+(s[i+1]-s[i])*(R/D);t[1]=t[0]+(s[r]-t[0])*(H/(t[0]-s[r]).norm());t[2]=t[1]-(t[0]-s[i])*((R-L)/(s[i]-t[0]).norm());t[3]=t[2]-(t[1]-t[0]);}}}int main(void) {#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);#endifscanf("%d",&n); F(i,1,n) p[i].Read();Graham();Rot();printf("%0.5lf\n",ans);int x=0; F(i,1,3) if (t[i].y<t[x].y||t[i].y==t[x].y&&t[i].x<t[x].x) x=i;F(i,0,3) printf("%0.5lf %0.5lf\n",t[(i+x)%4].x,t[(i+x)%4].y);return 0;}
给定一个任意的多边形,判断点在不在多边形内。
过当前点做一条射线。
看经过的节点的情况。
为了特判经过端点的情况,把所有线段的值较大的端点当成空心的点。
#include <cstdio>#include <cctype>#include <algorithm>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)#define INF 0x7fffffffint rd(void) {int x=0,f=1; char c=getchar();for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;for (;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}#define N 128int n,m;struct point {double x,y;point(double _x=0,double _y=0) {x=_x,y=_y;}friend point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}void Read(void) {scanf("%lf%lf",&x,&y);}}p[N];double det(point a,point b) {return a.x*b.y-a.y*b.x;}int Online(point a,point b,point x) {if (det(x-a,b-a)!=0) return 0;double minx=min(a.x,b.x),maxx=max(a.x,b.x);double miny=min(a.y,b.y),maxy=max(a.y,b.y);return minx<=x.x&&x.x<=maxx&&miny<=x.y&&x.y<=maxy;}int PNPoly(point x) {int c=0;F(i,0,n-1)if (Online(p[i],p[i+1],x))return 1;F(i,0,n-1) {double k=det(p[i+1]-p[i],x-p[i]);if (k>0&&p[i].y<=x.y&&x.y<p[i+1].y) c++;if (k<0&&p[i+1].y<=x.y&&x.y<p[i].y) c--;}return c!=0;}int main(void) {#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);#endifF(c,1,INF) {n=rd(); if (!n) break; m=rd();F(i,1,n) p[i].Read(); p[0]=p[n];if (n>=2) {double t=det(p[2]-p[1],p[1]-p[0]);if (t>0) F(i,0,n>>1) swap(p[i],p[n-i]);}if (c!=1) printf("\n");printf("Problem %d:\n",c);F(i,1,m) {point x; x.Read();if (PNPoly(x)) printf("Within\n"); else printf("Outside\n");}}return 0;}
如标题所示
使用判断。
记得判断第一个点与最后一个点的连边也要满足是凸的。
在直观理解叉积上,需要注意两点。
一个是平移的观点。
另一个是>0在下面,<0在上面,=0共线。
如果凸包可能是顺时针的,可能是逆时针的。
需要这样进行调整:
double t=det(p[2]-p[1],p[1]-p[0]);if (t>0) F(i,0,n>>1) swap(p[i],p[n-i]);
#include <cstdio>#include <cctype>#include <algorithm>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)int rd(void) {int x=0,f=1; char c=getchar();for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;for (;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}#define N 128int n;struct point {double x,y;point(double _x=0,double _y=0) {x=_x,y=_y;}friend point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}void Read(void) {x=rd(),y=rd();}}p[N];double det(point a,point b) {return a.x*b.y-a.y*b.x;}int is_convex(point *p,int n) {F(i,2,n) {double t=det(p[i]-p[i-1],p[i-1]-p[i-2]);if (t>0) return 0;}return 1;}int main(void) {#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);#endifwhile (1) {n=rd();if (!n) break;if (n<=2) {printf("concave\n");continue;}F(i,1,n) p[i].Read(); p[0]=p[n];/*double t=det(p[2]-p[1],p[1]-p[0]);if (t>0) F(i,0,n>>1) swap(p[i],p[n-i]);*/if (is_convex(p,n)) printf("convex\n"); else printf("concave\n");}return 0;}
在某块平面土地上有个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成的多边形面积最大。
首先,我们选择的四个点一定是多边形的顶点。所以我们先用Graham算法求出凸包。注意求凸包的正确姿势。det(a,b)<0,直接说明a在b的上面,类似的,有det(a,b)=0和det(a,b)>0。
然后,考虑怎么求最大的面积。我们可以考虑枚举一条对角线,暴力算左边和右边的最优情况。时间复杂度为,但是会TLE。
考虑根据凸包的性质进行优化。我们枚举对角线上的一个点,按照极角序枚举另一个点,那么最大的面积的点必然在单调的移动。所以优化到了。这貌似叫旋转卡壳?
关于实现上,多边形的面积考虑使用叉积来求。
#include <cstdio>#include <cmath>#include <algorithm>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)#define MIN -1e30#define N 2048int n;struct point {double x,y;point(double _x=0,double _y=0) {x=_x,y=_y;}friend point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}void Read(void) {scanf("%lf%lf",&x,&y);}}p[N],org;double det(point a,point b) {return a.x*b.y-a.y*b.x;}int cmp(point a,point b) {return det(a-org,b-org)<0;}double sqr(point a,point b,point c) {return fabs(det(b-a,c-a))/2;}point s[N]; int tot;void Graham(void) {int k=1; F(i,2,n) if (p[i].y<p[k].y||p[i].y==p[k].y&&p[i].x<p[k].x) k=i;swap(p[1],p[k]); org=p[1];sort(p+2,p+n+1,cmp);s[++tot]=p[1],s[++tot]=p[2];F(i,3,n) {while (tot>=2&&det(s[tot]-s[tot-1],p[i]-s[tot-1])>=0)s[tot--]=point();s[++tot]=p[i];}}double RC(void) {double ans=MIN;F(x,1,tot) {int a=x%tot+1;int b=(x+2)%tot+1;F(y,x+2,tot) {while (a%tot+1!=y&&sqr(s[x],s[y],s[a])<sqr(s[x],s[y],s[a%tot+1]))a=a%tot+1;while (b%tot+1!=x&&sqr(s[x],s[y],s[b])<sqr(s[x],s[y],s[b%tot+1]))b=b%tot+1;ans=max(ans,sqr(s[x],s[y],s[a])+sqr(s[x],s[y],s[b]));}}return ans;}int main(void) {#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);#endifscanf("%d",&n); F(i,1,n) p[i].Read();Graham();double ans=RC();printf("%.3lf\n",ans);return 0;}
关键掌握一下三分的写法。
double Query(point o) {int l=1,r=tot;while (r-l>=3) {int l_mid=(l+l+r)/3,r_mid=(l+r+r)/3;double _l=slope(s[l_mid],o);double _r=slope(s[r_mid],o);if (_l>_r)r=r_mid;else l=l_mid;}double res=0;F(i,l,r)res=max(res,slope(s[i],o));return res;}
大范围三分,小范围枚举,这样肯定是没有问题的。
#include <cstdio>#include <cctype>#include <algorithm>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)#define LL long long#define INF 1e30LL rd(void) {LL x=0,f=1; char c=getchar();for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;for (;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}#define N 131072int n; LL d;LL a[N],x[N];int tot;struct point {double x,y;point(double _x=0,double _y=0) {x=_x,y=_y;}friend point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}friend double operator ^ (point a,point b) {return a.x*b.y-a.y*b.x;}}s[N];void Add(point a) {while (tot>=2)if (((s[tot]-s[tot-1])^(a-s[tot-1]))<=0)s[tot--]=point();else break;s[++tot]=a;}double slope(point a,point b) {return (a.y-b.y)/(a.x-b.x);}double Query(point o) {int l=1,r=tot;while (r-l>=3) {int l_mid=(l+l+r)/3,r_mid=(l+r+r)/3;double _l=slope(s[l_mid],o);double _r=slope(s[r_mid],o);if (_l>_r)r=r_mid;else l=l_mid;}double res=0;F(i,l,r)res=max(res,slope(s[i],o));return res;}int main(void) {#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);#endifn=rd(),d=rd();F(i,1,n) a[i]=rd(),x[i]=rd();F(i,1,n) a[i]+=a[i-1];double sum=0;F(i,1,n) {Add(point(i*d,a[i-1]));double t=Query(point(i*d+x[i],a[i]));sum+=t;}printf("%.0lf\n",sum);return 0;}