【习题整理】计算几何基础

  • bzoj1074【Scoi2007】折纸

    • 思路:考虑倒着做,每次将在折叠的直线右边的扔掉,左边的点再对称一次加入;
    • 算几知识:求向量关于法向量的对称向量
    • 点$A$关于点$B$对称的点$C = 2B - A$
    • 如果要求$\vec{A}$关于法向量$\vec{l}$的对称向量$\vec{A‘}$;
    • 可以考虑都平移到原点
    • 利用点积求出$\vec{A}$在$\vec{l}$上的投影点$D$, 再将点$A$关于$D$对称到$A‘$;
    • $A‘$的坐标就是向量$\vec{A‘}$
    •  1 #include<bits/stdc++.h>
       2 #define db double
       3 #define eps 1e-6
       4 using namespace std;
       5 const int N=1<<9;
       6 int n,m,cnt,tmp;
       7 int dcmp(db x){return fabs(x)<=eps?0:x<0?-1:1;}
       8 struct point{
       9     db x,y;
      10     point(db _x=0,db _y=0):x(_x),y(_y){};
      11     point operator +(const point&A)const{return point(x+A.x,y+A.y);}
      12     point operator -(const point&A)const{return point(x-A.x,y-A.y);}
      13     point operator *(const db&a)const{return point(x*a,y*a);}
      14     db operator *(const point&A)const{return x*A.x+y*A.y;}
      15     db operator ^(const point&A)const{return x*A.y-y*A.x;}
      16 }p1[N],p2[N],q[N],qq[N];
      17 bool onleft(point A,point B,point C){
      18     return dcmp((C-B)^(A-B))>0;
      19 }
      20 point rev(point A,point B,point C){
      21     point D = C - B;
      22     db l2 = D*D;
      23     D = B + D*((A-B)*D/l2);
      24     return D*2 - A;
      25 }
      26 int main(){
      27     #ifndef ONLINE_JUDGE
      28     freopen("bzoj1074.in","r",stdin);
      29     freopen("bzoj1074.out","w",stdout);
      30     #endif
      31     scanf("%d", &n);
      32     for(int i=1;i<=n;i++)scanf("%lf%lf%lf%lf", &p1[i].x, &p1[i].y, &p2[i].x, &p2[i].y);
      33     scanf("%d", &m);
      34     for(int i=1;i<=m;i++){
      35         cnt=1;scanf("%lf%lf", &q[1].x, &q[1].y);
      36         for(int j=n;j;j--){
      37             tmp=0;
      38             for(int k=1;k<=cnt;k++)if(onleft(q[k],p1[j],p2[j])){
      39                 qq[++tmp] = q[k];
      40                 qq[++tmp] = rev(q[k],p1[j],p2[j]);
      41             }
      42             cnt=tmp;
      43             if(!cnt)break;
      44             for(int k=1;k<=cnt;k++)q[k]=qq[k];
      45         }
      46         int ans=0;
      47 //        puts("");
      48         for(int j=1;j<=cnt;j++){
      49 //            printf("%.2f %.2lf\n",q[j].x, q[j].y);
      50             if(dcmp(q[j].x)>0&&dcmp(q[j].y)>0&&dcmp(100-q[j].x)>0&&dcmp(100-q[j].y)>0){
      51                 ans ++;
      52             }
      53         }
      54         printf("%d\n",ans);
      55     }
      56     return 0;
      57 }

      bzoj1074

  • bzoj1094【Zjoi207】粒子运动
    • 思路:每个例子的路径是$k$段折线,枚举每队粒子和时间段计算最近距离;
    • 算几知识:
    • 1.求变化有的轨迹直接求出和圆的交点做出法向量求对称,对称的方法同上;
    • 2.求圆和向量的交点(保证有交):
    • 假设向量的起点$A$,方向$\vec{B}$,圆C的圆心为$O$,半径为$R$
    • 所以$( (A-O) + t \vec{B} )^2 = R^2$
    • 展开解即可
    •  1 #include<bits/stdc++.h>
       2 #define db double
       3 #define il inline
       4 using namespace std;
       5 const int N=110;
       6 int n,k;
       7 db R,t[N][N];
       8 struct point{
       9     db x,y;
      10     point(db _x=0,db _y=0):x(_x),y(_y){};
      11     point operator +(const point&A)const{return point(x+A.x,y+A.y);}
      12     point operator -(const point&A)const{return point(x-A.x,y-A.y);}
      13     point operator *(const db&a)const{return point(x*a,y*a);}
      14     db operator *(const point&A)const{return x*A.x+y*A.y;}
      15     db operator ^(const point&A)const{return x*A.y-y*A.x;}
      16 }O,p[N][N],v[N][N];
      17 il db cal(db a,db b,db c){return ( -b + sqrt(b*b-4*a*c) ) / a / 2; }
      18 il db len(point A){return sqrt(A*A);}
      19 il db solve(int i,int j,int k1,int k2,db tl,db tr){
      20     point v1 = v[i][k1], v2 = v[j][k2];
      21     point p1 = p[i][k1] + v1 * (tl - t[i][k1]);
      22     point p2 = p[j][k2] + v2 * (tl - t[j][k2]);
      23     point tv = v1-v2, tp = p1-p2; tr-=tl;
      24     db a=tv*tv,b=tv*tp*2,d=-b/a/2;
      25     if(fabs(a)<1e-9)return b > 0 ? len(tv*tr+tp) : len(tv*tl+tp);
      26     else {
      27         d = max(0.0, min(tr, d));
      28         return len(tv*d+tp);
      29     }
      30 }
      31 int main(){
      32     #ifndef ONLINE_JUDGE
      33     freopen("bzoj1094.in", "r", stdin);
      34     freopen("bzoj1094.out","w",stdout);
      35     #endif
      36     scanf("%lf%lf%lf",&O.x,&O.y,&R);
      37     scanf("%d%d",&n,&k);
      38     for(int i=1;i<=n;i++){
      39         scanf("%lf%lf%lf%lf",&p[i][0].x,&p[i][0].y,&v[i][0].x,&v[i][0].y);
      40         for(int j=1;j<=k+1;j++){
      41             point tp = p[i][j-1] - O, tv = v[i][j-1];
      42             db tx = cal(tv*tv, tp*tv*2, tp*tp-R*R);
      43             t[i][j] = t[i][j-1] + tx;
      44             p[i][j] = p[i][j-1] + tv*tx;
      45             point l = O - p[i][j]; swap(l.x,l.y),l.x=-l.x;
      46             v[i][j] = l * ((tv*l)/(l*l)) * 2 - tv;
      47         }
      48     }
      49     db ans = 1e18;
      50     for(int i=1;i<=n;i++)
      51     for(int j=1;j<=n;j++)if(i!=j){
      52         int k1=0,k2=0;
      53         while(k1<=k&&k2<=k){
      54             ans = min(ans, solve(i, j, k1, k2, max(t[i][k1],t[j][k2]), min(t[i][k1+1],t[j][k2+1])));
      55             if(t[i][k1+1]<t[j][k2+1])k1++;else k2++;
      56         }
      57     }
      58     printf("%.3lf\n",ans);
      59     return 0;
      60 }

      bzoj1094

  • bzoj1043【Hnoi2008】下落的圆盘
    • 思路:枚举每个圆盘后面落下的圆盘,求相交的弧度区域并之后统计没有被覆盖的部分;
    • 算几知识:
    • 极角:
    • 利用$atan2(y,x)$可以求得一个点的极角(弧度);
    • 极角范围$(-\pi,\pi]$,大小逆时针(-x轴,-x轴]不断增大;
    • x轴上半部分$+x$轴到$-x$轴不断增大,下半$-x$轴到$+x$轴不断增大;
    • 特别注意的是:$+x$轴为$0$,$-x$为$\pi$,$x$轴上方为正,下方为负,;
    • 如果一个区间跨越了-x轴,那么需要分成两个区间处理;
    • 求两圆交点及相交的极角弧度范围:
    • 设小圆$O_{1}$半径$r_{1}$,大圆$O_{2}$半径$r_{2}$,圆心距$|O1O2| = d$,两个交点分别为$P_{1}$,$P_{2}$;
    • 首先判断位置关系:$d > r_{1} + r_{2}$相离,$d < r_{2} - r_{1}$包含,都没有交点;
    • (不考虑相切)然后:
    • 在$\triangle O1O2P1$中用余弦定理算出$angle P_{1}O_{1}O_{2}$,利用$\vec{O_{1}O_{2}}$旋转调整可得$\vec{O_{1}P_{1}} ,    \vec{O_{1}P_{2}}$ ,可以算出$O_{1}O_{2}$
    •  1 #include<bits/stdc++.h>
       2 #define db double
       3 #define eps 1e-9
       4 using namespace std;
       5 const int N=1010;
       6 const db pi = acos(-1);
       7 int n,tot1[N],tot2[N],vis[N];
       8 db sub2[N][N<<2],cnt[N<<2];
       9 struct point{
      10     db x,y;
      11     point(db _x=0,db _y=0):x(_x),y(_y){};
      12     point operator +(const point&A)const{return point(x+A.x,y+A.y);}
      13     point operator -(const point&A)const{return point(x-A.x,y-A.y);}
      14     db operator *(const point&A)const{return x*A.x+y*A.y;}
      15     db operator ^(const point&A)const{return x*A.y-y*A.x;}
      16     point operator *(const db&a)const{return point(x*a,y*a);}
      17 }sub1[N][N<<2];
      18 struct circle{point o;db r;}c[N];
      19 int dcmp(db x){return fabs(x)<eps?0:x<0?-1:1;}
      20 db len(point A){return sqrt(A*A);}
      21 point rotate(point A,db cos,db sin){return point(A.x*cos-A.y*sin, A.y*cos+A.x*sin);}
      22 void ins(int i,point p1,point p2){
      23     db l = atan2(p1.y,p1.x), r = atan2(p2.y,p2.x);
      24     sub2[i][++tot2[i]] = l;
      25     sub2[i][++tot2[i]] = r;
      26     if(dcmp(l-r)>0){
      27         sub1[i][++tot1[i]]=point(-pi,r);
      28         sub1[i][++tot1[i]]=point(l,pi);
      29     }else sub1[i][++tot1[i]]=point(l,r);
      30 }
      31 void solve(int i,int j){
      32     if(dcmp(c[i].r-c[j].r)>0)swap(i,j);
      33     point td = c[j].o - c[i].o,p0,p1,p2;
      34     db d = len(td), r1=c[i].r, r2=c[j].r;
      35     if(dcmp(d-r1-r2)>=0)return ;
      36     if(dcmp(d-r2+r1)<=0){if(i<j)vis[i]=1;return ;}
      37     db Cos = (td*td + r1*r1 - r2*r2) /d /r1 /2  ;
      38     db Sin = sqrt(1-Cos*Cos);
      39     p0 = td * (r1/d);
      40     p1 = c[i].o + rotate(p0,Cos,-Sin);//
      41     p2 = c[i].o + rotate(p0,Cos,Sin);
      42     if(i<j)ins(i,p1-c[i].o, p2-c[i].o);
      43     else ins(j,p2-c[j].o, p1-c[j].o);
      44 }
      45 int main(){
      46     freopen("bzoj1043.in","r",stdin);
      47     freopen("bzoj1043.out","w",stdout);
      48     scanf("%d",&n);
      49     for(int i=1;i<=n;i++){
      50         scanf("%lf%lf%lf",&c[i].r,&c[i].o.x,&c[i].o.y);
      51         for(int j=i-1;j;j--)solve(j,i);
      52     }
      53     db ans = 0;
      54     for(int i=1;i<=n;i++){
      55         if(vis[i])continue;
      56         sub2[i][++tot2[i]]=-pi;
      57         sub2[i][++tot2[i]]=pi;
      58         sort(sub2[i]+1,sub2[i]+tot2[i]+1);
      59         for(int j=1;j<=tot2[i];j++)cnt[j]=0;
      60         for(int j=1;j<=tot1[i];j++){
      61             int p1 = lower_bound(sub2[i]+1,sub2[i]+tot2[i]+1,sub1[i][j].x) - sub2[i];
      62             int p2 = lower_bound(sub2[i]+1,sub2[i]+tot2[i]+1,sub1[i][j].y) - sub2[i];
      63             cnt[p1]--,cnt[p2]++;
      64         }
      65         db all = 0;
      66         for(int j=1;j<tot2[i];j++){
      67             cnt[j]+=cnt[j-1];
      68             if(!cnt[j])all += sub2[i][j+1]-sub2[i][j];
      69         }
      70         ans += all * c[i].r;
      71     }
      72     printf("%.3lf\n", ans);
      73 }

      bzoj1043

原文地址:https://www.cnblogs.com/Paul-Guderian/p/10257528.html

时间: 2024-08-27 02:56:57

【习题整理】计算几何基础的相关文章

nyis oj 68 三点顺序 (计算几何基础)

三点顺序 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描写叙述 如今给你不共线的三个点A,B,C的坐标,它们一定能组成一个三角形,如今让你推断A,B,C是顺时针给出的还是逆时针给出的? 如: 图1:顺时针给出 图2:逆时针给出 <图1>                   <图2> 输入 每行是一组測试数据,有6个整数x1,y1,x2,y2,x3,y3分别表示A,B,C三个点的横纵坐标.(坐标值都在0到10000之间) 输入0 0 0 0 0 0表示输入

习题(3-3) 计算(a+b)*c的值

题目 - 习题(3-3) 计算(a+b)*c的值   来源 计算概论B 2010 描写叙述 计算表达式(a+b)*c的值,当中a, b, c均为整数,且a,b,c的值介于-10000和10000之间(不含-10000和10000) 关于输入 输入仅一行.包含三个整数a, b和c 关于输出 输出也是一行.即表达式的值 样例输入 2 3 5 样例输出 25 #include <stdio.h> int main(){ int a, b, c; scanf("%d%d%d", &

计算几何基础——【点积和叉积的用处】

计算几何是算法竞赛的一大块,而叉积是计算机和的基础. 首先叉积是计算说向量之间的叉积,那么我们可以这样定义向量,以及向量的运算符重载. struct Point { double x,y; Point(double x=0,double y=0):x(x),y(y) {} }; typedef Point Vector; Vector operator + (Vector A,Vector B) { return Vector(A.x+B.x,A.y+B.y); } Vector operato

知识点 - 计算几何基础

知识点 - 计算几何基础 讲义 点 我们把点 \(\mathbf r\) 看成从 \(\mathbf 0\) 到 \(\mathbf r\)的向量 \(\vec{\mathbf r}\) #define ftype long double struct point2d { ftype x, y; point2d() {} point2d(ftype x, ftype y): x(x), y(y) {} point2d& operator+=(const point2d &t) { x +=

【kuangbin专题】计算几何基础(极角相关)

[POJ 1696] Space Ants [题目大意] 给定多个点,对他们按照下面的规则排序,每个都在前一个点组成的左边,并且连线不相交(典型如图) [题目分析] 不断进行极角排序,不断选取一定区域内最符合要求的解 [代码] 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #define ll double 5 using namespace std; 6 const double eps

[华为机试练习题]46.计算二进制数的0的个数

题目 描述: 输入一个10进制数字,请计算该数字对应二进制中0的个数,注意左数第一个1之前的所有0都不需要计算.不需要考虑负数的情况. 题目类别: 位运算 难度: 初级 运行时间限制: 无限制 内存限制: 无限制 阶段: 入职前练习 输入: 要计算的十进制非负数 输出: 二进制中第一个1之后0 的个数 样例输入: 2 样例输出: 1 代码 /*--------------------------------------- * 日期:2015-07-03 * 作者:SJF0115 * 题目:计算二

计算几何及其应用——计算几何基础

写在前面:当时开计算几何这个专题神奇的从解析几何开始了,然后最近发现<计算几何及应用(金博)>这本书前面那章忽略掉了一些重要的东西比如说点定位.半平面相交之类的东西,恰好还有一些和计算几何扯上边但是不需要算法的简单题目没有整理,故在此开辟一块小空间. 我们再来看一道有关几何的问题.(Problem source:hdu2073)    数理分析:虽然这道题异常的简单,基本算不上计算几何这个专题当中的题目,但是把它拿到这里来,是源于这道简单几何题的思路其实体现了计算几何整个体系中比较重要的思维.

BZOJ_1610_[Usaco2008_Feb]_Line连线游戏_(计算几何基础+暴力)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1610 给出n个点,问两两确定的直线中,斜率不同的共有多少条. 分析 暴力枚举直线,算出来斜率放在k数组里面(斜率不存在记为INF),然后去个重统计个数就行了. 其实特水... 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=200+5; 5 const double eps=1e-8,INF=0x7f

课本第四章-不定积分习题整理

三角函数相关类型 1. 利用三角变化以及三角恒等式,比如 $\sin^2 x + \cos^2 x=1$ 以及二倍角公式,和差化积,积化和差. 比如:  4-1 的 1-(5), 令 $1=\sin^2 x+ \cos^2 x$ 即可; 4-1 的 1-(6), 二倍角公式 4-1 的 1-(7), 二倍角公式 $\cos 2x =\cos^2 x  -\sin^2 x$ 4-2 的 1-(12), 积化和差公式 4-3 的 1-(5), $\tan^2 x=\sec^2 x -1$ 2. $\