1. 程式人生 > >POJ2318 (二分加叉積使用)

POJ2318 (二分加叉積使用)

題目連結

題目大意:給你一個矩形和一些線段,給的這些線段將矩形分割為從左到右的若干個部分(不會相交,點不會再線上,題意給出了),之後給出一些玩具的座標,求分割的若干部分每個部分的玩具數量。

題解:這是一個計算幾何的水題,考一些基礎問題,我們注意,題目上給線段的順序是從左到右給出的,我們可以考慮的是每一個點(玩具)是在這條線的左邊還是右邊,(一定會存在一個分界使它的左邊的線段都在玩具的右邊,它右邊的玩具都在玩具的左邊)

於是我們能想出來這種情況下我們要用二分來寫:

然後我們根據叉積判斷點和線段的關係(我們可以將點減去線段的起點和原線段組成兩個同七點的向量,然後我們根據叉積的性質:

若P×Q > 0 , 則P在Q的順時針方向;

若P×Q < 0 , 則P在Q的逆時針方向;

若P×Q = 0 , P與Q共線,可能是同向也可能是反向

因為題目上說了,玩具保證不會落在分界線上,所以不用考慮)

特別注意:本題的陣列有點兒多吧,注意初始化每一個數組。

AC程式碼如下:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int mx = 666666;

int u[mx] , v[mx] , ans[mx];

int chachen(int x1 , int y1 , int x2 , int y2)
{
    return x1 * y2 - x2 * y1;
}

int main()
{
    int n , m , x1 , y1 , x2 , y2 , flag = 0 ;
    while(scanf("%d%d%d%d%d%d",&n,&m,&x1,&y1,&x2,&y2) == 6)
    {
        if(flag)
            puts("");
        flag = 1;
        memset(ans,0,sizeof(ans));
        for(int i = 0 ; i < n ; i ++)
        {
            scanf("%d %d",&u[i],&v[i]);
        }
        int x , y ;
        for(int i = 1 ; i <= m ; i ++)
        {
            cin>>x>>y;
            int high = n , mid , low = 0 ;
            while(low < high)
            {
                mid = (low + high) / 2 ;
                if(chachen(u[mid] - x , y1 - y , v[mid] - x , y2 - y) <= 0)
                    high = mid;
                else
                    low = mid + 1 ;

            }
            ans[low]++;
        }
        for(int i = 0 ; i <= n ; i ++)
        {
            printf("%d: %d\n",i,ans[i]);
        }
    }
    return 0 ;
}

有的可能就是sort掃一遍然後輸出就能過,可能使後臺資料太水吧,那個我看要900多Ms,但是用二分的話差不多500Ms執行完