POJ2398 计算几何外积+二分

题意:给n个线段m个玩具和x1,y1,x2,y2 每条线段起点纵坐标y1 ,终点纵坐标y2  

玩具箱的边界由n条线段+(x1,y1)-(x1,y2),(x2,y1)-(x2,y2)共n+2条线段形成 n+1个区域

保证n个线段都在x1,y1,x2,y2内,不会有玩具在边上或超出边界

输出有多少个区域的玩具数目有K个 K>0 的任意数


思路:假设玩具是点P 红色是区域的号码,蓝色是线段的号码

要判断P在哪个区域里,先编好号码,不然二分会乱


对每个玩具进行l=0,r=n 共n+1个区域 二分找使得外积<0的号码最小的线段即可


对了,这题N条线段得先排序再二分


#include
   
   
    
    
#include
    
    
#include
     
     
      
      
#include
      
      
       
       
#include
       
       
         #include 
        
          #include 
         
           #include 
          
            #define MOD 1e9+7 #define MaxN 100000 #define ll long long #define INF 0x3f3f3f3f//1e9大一点 #define scann(d) scanf("%d",&d) #define scanl(d) scanf("%I64d",&d) using namespace std; const double eps = 1e-8; const double PI = acos(-1.0); const double e = 2.718281828459; inline int sgn(double a); inline ll gcd(ll a,ll b); inline ll mod_pow(ll x,ll n,ll mod); //快速幂 余数 inline int b_s1(int *a,int l,int r,int k); //二分查找 [l,r)找k 找到返回下标 class point { public: int x,y; point() { } point(int a,int b) { x=a,y=b; } point operator -(const point &b)const { return point(x - b.x,y - b.y); } //叉积 int operator ^(const point &b)const { return x*b.y - y*b.x; } //点积 int operator *(const point &b)const { return x*b.x + y*b.y; //绕原点旋转角度B(弧度值),后x,y的变化 } } points[1005]; struct line { point s,e; line() {} line(point _s,point _e) { s = _s; e = _e; } } lines[1005]; ll xmult(point p0,point p1,point p2) //计算p0p1 X p0p2 { return (p1-p0)^(p2-p0); } bool C(int mid) { // if()return true; return false; } bool cmp(line a,line b) { if(a.s.x!=b.s.x)return a.s.x<b.s.x; else return a.e.x 
           >n) { if(n==0) break; int m,x1,y1,x2,y2; cin>>m>>x1>>y1>>x2>>y2; for(int i=0; i 
             
               >t1>>t2; lines[i].s=point(t1,y1); lines[i].e=point(t2,y2); } sort(lines,lines+n,cmp); lines[n].s=point(x2,y1); lines[n].e=point(x2,y2); lines[n+1].s=point(x1,y1); lines[n+1].e=point(x1,y2); map 
              
                m1; m1.clear(); while(m--) { int pt1,pt2; cin>>pt1>>pt2; point t=point(pt1,pt2); //二分死大头 int l=0;//左 int r=n;//右 int mid=0;//中间 int count=0;//二分次数; int ans=0;//答案的下标 while(l<=r) { count++; mid=(l+r)/2; // cout<<count<<" l:"<<l<<" r:"<<r<<" mid:"<<mid<<endl; if(xmult(t,lines[mid].s,lines[mid].e)<0)//bool C(mid); { ans=mid;//二分找满足if条件的最小mid r=mid-1; } else { //ans1=mid;//二分找满足else条件的最大mid l=mid+1; } } m1[ans]++; } cout<<"Box"<<endl; map 
               
                 m2; for(map 
                
                  ::iterator poi=m1.begin(); poi!=m1.end(); poi++) { m2[poi->second]++; } for(map 
                 
                   ::iterator poi=m2.begin(); poi!=m2.end(); poi++) { cout< 
                  
                    first<<": "< 
                   
                     second<<endl; } } return 0; } inline int sgn(double a) { return a < -eps ? -1 : a < eps ? 0 : 1; } inline ll gcd(ll a,ll b) { return a==0?b:gcd(b%a,a); } ll mod_pow(ll x,ll n,ll mod)//快速幂 余数 { ll res=1; while(n>0) { if(n&1)//n的二进制最右位是1,即奇数 res=res*x%mod; x=x*x%mod; n=n>>1; //相当于n/=2; } return res; } int b_s1(int *a,int l,int r,int k)// 二分查找 [l,r)找k 找到返回下标 log(n); { int m; while(l<r) { m=l+(r-l)/2; if(a[m]==k) return m; else if(a[m]<k) l=m+1; else r=m; } return -1; }ssssss 
                    
                   
                  
                 
                
               
              
           
          
         
       
      
      
     
     
   
   



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值