POJ 2318 几何初步 + 二分 及其 姊妹题 POJ 2398

叉积+二分


如果toys在当前板的左边 cross(L,toys,U) < 0

反之在右边会 > 0

根据这个,我们进行二分;

为什么最后得到的不是mid而是l呢?

我们来看这张图.

加入现在是 l = 2 , r = 5;mid = 3; toy在4纸板右边,5纸板左边,

执行l = l +1 = 3, r = 5, mid = 4;依然>0 执行, 

l = l + 1 = 4,r = 5, mid = 4; 依然大于0 ,执行

l = l + 1 = 5, r= 5, 退出; 此时l = 5, 之前toy确实在l右边,可是现在在它左边了.(有的情况还是会在右边)

所以我们后面要加一个判断:

if(cross(CardB[r].L, Toys, CardB[r].U) < 0)
        N_Toys[l]++;
else
        N_Toys[l+1]++;

显然,我们同样可以:

if(cross(CardB[r].L, Toys, CardB[r].U) > 0)
        N_Toys[r+1]++;
else
        N_Toys[r]++;

那么,如果利用mid 改怎么改写代码呢?

        for(int i = 0; i < m; i++)
        {
            l = 0, r = n-1;
            scanf("%d%d",&Toys.x,&Toys.y);
            while(l <= r)
            {
                mid = (l + r) >> 1;
                if(cross(CardB[mid].L, Toys, CardB[mid].U) > 0)
                    l = mid + 1;
                else
                    r = mid - 1;
            }
            if(cross(CardB[mid].L, Toys, CardB[mid].U) > 0)
                N_Toys[mid+1]++;
            else
                N_Toys[mid]++;
        }

/*
 *POJ 2318
 *fuqiang
 *几何初步
 *2013/8/2
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 5000+3;
const double PI = 4.0*atan(1.0);
const double eps = 1e-8;

struct point
{
    int x;
    int y;
} Toys;
struct Line
{
    point U;
    point L;
} CardB[maxn];
int N_Toys[maxn];

int cross(const point &p0, const point &p1, const point &p2)  //计算叉积
{
    return (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y);
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
#endif
    int n,m,x1,y1,x2,y2;
    while(scanf("%d",&n) && n)
    {
        scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2);
        for(int i = 0; i < n; i++)
        {
            scanf("%d%d", &CardB[i].U.x, &CardB[i].L.x);
            CardB[i].U.y = y1;
            CardB[i].L.y = y2;
        }
        memset(N_Toys,0,sizeof(N_Toys));
        int l, r, mid, ans, p;
        for(int i = 0; i < m; i++)
        {
            l = 0, r = n-1;
            scanf("%d%d",&Toys.x,&Toys.y);
            while(l < r)
            {
                mid = (l + r) >> 1;
                if(cross(CardB[mid].L, Toys, CardB[mid].U) > 0)
                    l = mid + 1;
                else
                    r = mid;
            }
            if(cross(CardB[r].L, Toys, CardB[r].U) < 0)
                N_Toys[l]++;
            else
                N_Toys[l+1]++;
        }
        for(int i = 0; i <= n; i++)
        {
            printf("%d: %d\n",i,N_Toys[i]);
        }
        printf("\n");
    }
}

还有个更好的点子,别人的代码:

将最后一个点也作为纸板,此时 我们只需要返回l:

while (l <= r)
{
    mid = (l + r) >> 1;

    if ( cal (low[mid], high[mid], cc) > 0 )
        l = mid + 1;
    else r = mid - 1;
    }
    return l;
}

POJ 2398

加个排序,统计后输出,注意t>0

/*
 *POJ 2318
 *fuqiang
 *几何初步
 *2013/8/2
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 5000+3;
const double PI = 4.0*atan(1.0);
const double eps = 1e-8;

struct point
{
    int x;
    int y;
} Toys;
struct Line
{
    point U;
    point L;
} CardB[maxn];
int N_Toys[maxn];

int cross(const point &p0, const point &p1, const point &p2)  //计算叉积
{
    return (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y);
}

int cmp(Line a, Line b)//sort...
{
    return a.L.x < b.L.x;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
#endif
    int n,m,x1,y1,x2,y2;
    while(scanf("%d",&n) && n)
    {
        scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2);
        for(int i = 0; i < n; i++)
        {
            scanf("%d%d", &CardB[i].U.x, &CardB[i].L.x);
            CardB[i].U.y = y1;
            CardB[i].L.y = y2;
        }
        sort(CardB,CardB+n,cmp); //sort
        memset(N_Toys,0,sizeof(N_Toys));
        int l, r, mid, ans, p;
        for(int i = 0; i < m; i++)
        {
            l = 0, r = n-1;
            scanf("%d%d",&Toys.x,&Toys.y);
            while(l <= r)
            {
                mid = (l + r) >> 1;
                if(cross(CardB[mid].L, Toys, CardB[mid].U) > 0)
                    l = mid + 1;
                else
                    r = mid - 1;
            }
            if(cross(CardB[mid].L, Toys, CardB[mid].U) > 0)
                N_Toys[mid+1]++;
            else
                N_Toys[mid]++;
        }
        sort(N_Toys,N_Toys+n+1);
        printf("Box\n");
        int st = 0;
        while(N_Toys[st] == 0)
            st++;
        for(int i = st; i <= n; )
        {
            int num = 1;
            printf("%d: ",N_Toys[i]);
            for(int j = i++; j <= n; j++,i++)
            {
                if(N_Toys[i]==N_Toys[j])
                    num++;
                else
                    break;
            }
            printf("%d\n",num);
        }
//        printf("\n");
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值