zoukankan      html  css  js  c++  java
  • Codeforces 1036E Covered Points (线段覆盖的整点数)【计算几何】

    <题目链接>

    <转载于 >>>  >

    题目大意:

    在二维平面上给出n条不共线的线段(线段端点是整数),问这些线段总共覆盖到了多少个整数点。

    解题分析:

    用GCD可求的某条给定线段上有多少个整数点,理由如下:

    GCD(n,m)为n与m的最大公约数,通过辗转相除法求得。令g=GCD(n,m); n=x*g, m=y*g.所以将横坐标分为g个x份,将纵坐标分为g个y份。所以,本题线段覆盖的整数点个数为 g+1 (因为包含端点,如果不包含端点就为 g-1 )。

    但是这样求的的覆盖点数是包含重复点数的,所以我们可以对每条线段再遍历一次,求的它与它之后线段的不重复交点个数,然后用总的交点个数减去这些重复计算的交点,就是答案了。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<iostream>
      5 #include<cmath>
      6 #include<vector>
      7 #include<queue>
      8 #include<set>
      9 #include<map>
     10 using namespace std;
     11 #define eps 1e-6
     12 #define For(i,a,b) for(int i=a;i<=b;i++)
     13 #define Fore(i,a,b) for(int i=a;i>=b;i--)
     14 #define lson l,mid,rt<<1
     15 #define rson mid+1,r,rt<<1|1
     16 #define mkp make_pair
     17 #define pb push_back
     18 #define sz size()
     19 #define met(a,b) memset(a,b,sizeof(a))
     20 #define iossy ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)     //提高cin、cout的效率
     21 #define fr freopen
     22 #define pi acos(-1.0)
     23 #define Vector Point
     24 typedef pair<int,int> pii;
     25 const long long linf=1LL<<62;
     26 const int iinf=1<<30;
     27 const double dinf=1e17;
     28 const int Mod=1e9+9;
     29 typedef long long ll;
     30 typedef long double ld;
     31 const int maxn=1000005;
     32 int n;
     33 struct Point{
     34     ll x,y;
     35     int id;
     36     Point(ll x=0,ll y=0):x(x),y(y) {}
     37     Point operator - (const Point &a)const { return Point(x-a.x,y-a.y);}
     38     bool operator == (const Point &a)const { return x==a.x && y==a.y; }
     39 };
     40  
     41 ll gcd(ll a,ll b){
     42     while(b>0){
     43         ll t=b;b=a%b;a=t;
     44     }
     45     return a;
     46 }
     47  
     48 ll Cross(Vector a,Vector b){   //向量叉乘
     49     return a.x*b.y-a.y*b.x;
     50 }
     51 ll Dot(Vector a,Vector b) {    //向量相乘
     52     return a.x*b.x+a.y*b.y;
     53 }
     54 bool onsg(Point p,Point a1,Point a2){     //判断点p是否在a1,a2组成的线段上
     55     return Cross(a1-p,a2-p)==0 && Dot(a1-p,a2-p)<0;   
     56     //共线且反向
     57 }
     58 void ck(ll &c){
     59     if(c>0) c=1;
     60     else if(c<0) c=-1;
     61 }
     62 int Ins(Point a1,Point a2,Point b1,Point b2){     //判断两个线段是否有交点
     63     if(a1==b1 || a1==b2 || a2==b1 || a2==b2) return 1;   //如果有端点相等,那么线段必然有交点
     64     if(onsg(a1,b1,b2) || onsg(a2,b1,b2) || onsg(b1,a1,a2) || onsg(b2,a1,a2)) return 1;    //如果有端点在另一条线段上,那么这两条线段必然有交点  
     65      
     66     ll c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1);      //用c1*c2<0来判断b1,b2是否在a1~a2线段的两边
     67  
     68     ll c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);      //用c3*c4<0来判断a1,a2是否在b1~b2线段的两边
     69     ck(c1);ck(c2);ck(c3);ck(c4);
     70     return c1*c2<0 && c3*c4<0;
     71 }
     72  
     73 set<pair<ll,ll> >c;
     74 void chk(Point p,Vector v,Point q,Vector w){     //找到两条线段的交点坐标
     75     Vector u=p-q;
     76     ll v1=Cross(w,u),v2=Cross(v,w);
     77     if(abs(v1*v.x)%v2!=0 || abs(v1*v.y)%v2!=0) return ;
     78     ll xx,yy;
     79     xx=p.x+v.x*v1/v2;yy=p.y+v.y*v1/v2;
     80     c.insert(mkp(xx,yy));
     81 }
     82  
     83 struct segm{
     84     Point p1,p2;
     85 };
     86  
     87 segm ss[maxn];
     88 Point p1,p2;
     89 void solve(){
     90     iossy;    
     91     cin>>n;
     92     int ans=0;
     93     For(i,1,n){
     94         cin>>p1.x>>p1.y>>p2.x>>p2.y;
     95         ss[i].p1=p1;ss[i].p2=p2;
     96         ans+=gcd(abs(ss[i].p2.x-ss[i].p1.x),abs(ss[i].p2.y-ss[i].p1.y))+1;    //此处也可以直接用  __gcd()函数
     97     }//利用gcd找出所有线段所能覆盖的整数点的总数
     98  
     99     For(i,1,n){
    100         c.clear();    //每次清空set
    101         For(j,i+1,n){
    102             int ct=Ins(ss[i].p1,ss[i].p2,ss[j].p1,ss[j].p2);
    103             if(ct) chk(ss[i].p1,ss[i].p2-ss[i].p1,ss[j].p1,ss[j].p2-ss[j].p1);   
    104             //如果线段i与线段j有交点的话,将线段i与线段i+1~n的所有不重复的整数交点个数找出来
    105         }                                                                        
    106         ans-=c.sz;  
    107     }
    108     cout<<ans<<endl;
    109 }
    110  
    111 int main(){
    112     solve();
    113     return 0;
    114 }

      

    2018-09-09

  • 相关阅读:
    冲刺第九天
    冲刺第八天
    寻找小水王
    冲刺第七天
    冲刺第六天
    冲刺第五天
    寻找水王程序二
    学习进度条(第十二周)
    寻找水王程序一
    学习进度条(第十一周)
  • 原文地址:https://www.cnblogs.com/00isok/p/9613583.html
Copyright © 2011-2022 走看看