• cogs1600 奶牛冰壶 计算几何


    链接:http://cogs.pro/cogs/problem/problem.php?pid=1600

    题意:两方打冰壶,分别计算出双方用三个以上球夹住的对方球的数量。

    首先我们要明确一点:这个问题可以转化为求出凸包内包含的点的数量。理由很显然:如果你用三个不在凸包外延的点夹住了某颗石头,比它们范围更大的凸包一定也可以夹住它。因此问题转化为求出凸包内包含的另一方点的数量。首先,凸包可以在$O(nlogn)$时间内求出,因此问题就转化为如何判断点是否在凸包内。

    一种判断点在多边形之内的方法是射线法,即由该点向任意方向射出一条射线,判断与多边形交点数目,如果是奇数次相交证明在多边形内部。但这样会带来一个问题:如果射线与图形非规范相交需要再引出射线,而如何判断是否规范相交又是个大问题,这样会引起码量急剧上升,时间效率却不太好。

    为此,这里介绍一种更快、难度更小、范围更广(甚至自交的多边形也可以)的判断方法:转角法。基本思想就是看多边形转一圈是相对这个点转了多少,$360°$为在图形外,$0°$为在图形内,$180°$为在图形上。但是如果直接计算,这样会涉及大量反三角函数,效率低还是其次,更大的问题是精度爆炸成GTX690。因此,我们实际上的操作是假想这个点拉出一条向右的射线,正着过次数+1,反着过次数-1,最后只要不是0,点就在多边形里面了。具体实现可以参考代码。

    问题的解法很明显了。首先分别求出双方冰壶组成的凸包,随后对于每一个点,判断是否被对方凸包覆盖。可能有人会担心超时,因为最坏情况下检查是$O(n^2)$的,但实际上算法效果非常好,不但没有超时还上了榜。

    本题最大的坑点在于:边界线计入图形内部……

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<vector>
      6 #include<cmath>
      7 using namespace std;
      8 const int maxn=50005;
      9 const double eps=1e-8;
     10 int n;
     11 struct point
     12 {
     13     double x,y;
     14     bool operator<(const point &b)const 
     15     {
     16         return x==b.x?y<b.y:x<b.x;
     17     }
     18     friend point operator -(point a,point b)
     19     {
     20         return (point){a.x-b.x,a.y-b.y};
     21     }
     22 }pa[maxn],pb[maxn];
     23 vector<point>convexa,convexb;
     24 double dis(point a,point b)
     25 {
     26     return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
     27 }
     28 double cross(point a,point b)
     29 {
     30     return a.x*b.y-b.x*a.y;
     31 }
     32 double across(point a,point b,point c)
     33 {
     34     return cross(b-a,c-a)>eps;
     35 }
     36 int s[maxn],vis[maxn];
     37 void graham()
     38 {
     39     memset(vis,0,sizeof(vis));
     40     sort(pa+1,pa+n+1);
     41     s[0]=0;s[++s[0]]=1;s[++s[0]]=2;
     42     for(int i=3;i<=n;i++)
     43     {
     44         while(s[0]>1&&!across(pa[s[s[0]]],pa[i],pa[s[s[0]-1]]))s[0]--;
     45         s[++s[0]]=i;
     46     }
     47     for(int i=1;i<=s[0];i++)vis[s[i]]=1,convexa.push_back(pa[s[i]]);
     48     s[0]=0;s[++s[0]]=n;s[++s[0]]=n-1;
     49     for(int i=n-2;i;i--)
     50     {
     51         while(s[0]>1&&across(pa[s[s[0]]],pa[s[s[0]-1]],pa[i]))s[0]--;
     52         s[++s[0]]=i;
     53     }
     54     for(int i=1;i<=s[0];i++)
     55         if(!vis[s[i]])convexa.push_back(pa[s[i]]);
     56     memset(vis,0,sizeof(vis));
     57     sort(pb+1,pb+n+1);
     58     s[0]=0;s[++s[0]]=1;s[++s[0]]=2;
     59     for(int i=3;i<=n;i++)
     60     {
     61         while(s[0]>1&&!across(pb[s[s[0]]],pb[i],pb[s[s[0]-1]]))s[0]--;
     62         s[++s[0]]=i;
     63     }
     64     for(int i=1;i<=s[0];i++)vis[s[i]]=1,convexb.push_back(pb[s[i]]);
     65     s[0]=0;s[++s[0]]=n;s[++s[0]]=n-1;
     66     for(int i=n-2;i;i--)
     67     {
     68         while(s[0]>1&&across(pb[s[s[0]]],pb[s[s[0]-1]],pb[i]))s[0]--;
     69         s[++s[0]]=i;
     70     }
     71     for(int i=1;i<=s[0];i++)
     72         if(!vis[s[i]])convexb.push_back(pb[s[i]]);
     73 }
     74 int dcmp(double x)
     75 {
     76     if(fabs(x)<eps)return 0;
     77     return x<0?-1:1;
     78 }
     79 double dot(point a,point b)
     80 {
     81     return a.x*b.x+a.y*b.y;
     82 }
     83 bool onsegment(point p,point a1,point a2)
     84 {
     85     return dcmp(cross(a1-p,a2-p))==0&&dcmp(dot(a1-p,a2-p))<0;
     86 }
     87 int ispointinpolygon(point p,vector<point>tmp)
     88 {
     89     int wn=0,t=tmp.size();
     90     for(int i=0;i<t;i++)
     91     {
     92         if(onsegment(p,tmp[i],tmp[(i+1)%t]))return 1;
     93         int k=dcmp(cross(tmp[(i+1)%t]-tmp[i],p-tmp[i]));
     94         int d1=dcmp(tmp[i].y-p.y),d2=dcmp(tmp[(i+1)%t].y-p.y);
     95         if(k>0&&d1<=0&&d2>0)wn++;
     96         if(k<0&&d2<=0&&d1>0)wn--;
     97     }
     98     return wn!=0;
     99 }
    100 int haha()
    101 {
    102     freopen("curling.in","r",stdin);
    103     freopen("curling.out","w",stdout);
    104     scanf("%d",&n);
    105     for(int i=1;i<=n;i++)scanf("%lf%lf",&pa[i].x,&pa[i].y);
    106     for(int i=1;i<=n;i++)scanf("%lf%lf",&pb[i].x,&pb[i].y);
    107     graham();
    108     int ans1=0,ans2=0;
    109     for(int i=1;i<=n;i++)ans2+=ispointinpolygon(pa[i],convexb),ans1+=ispointinpolygon(pb[i],convexa);
    110     printf("%d %d
    ",ans1,ans2);
    111 }
    112 int sb=haha();
    113 int main(){;}
    cogs1600
  • 相关阅读:
    VS2013中使用本地IIS+域名调试ASP.NET项目
    layui框架中layer父子页面交互的方法分析
    Layer组件多个iframe弹出层打开与关闭及参数传递
    Android新版本特性以及注意事项
    【Android Studio安装部署系列】三十、从Android studio2.2.2升级到Android studio3.0之路
    【Android Studio安装部署系列】二十八、Android Studio查看其它APP的布局结构
    【Android Studio安装部署系列】二十七、Android studio修改项目名称和包名
    Beetle简单构建TCP服务
    【Android Studio安装部署系列】十三、Android studio添加和删除Module 2
    LeetCode242——Valid Anagram
  • 原文地址:https://www.cnblogs.com/Loser-of-Life/p/7291375.html
Copyright © 2020-2023  润新知