2017 ICPC North American Qualifier Contest A - Birthday Cake 計算幾何

 A - Birthday Cake

https://open.kattis.com/problems/birthdaycake

On his birthday, John’s parents made him a huge birthday cake! Everyone had a wonderful dinner, and now it’s time to eat the cake. There are nn candles on the cake. John wants to divide the cake into nn pieces so that each piece has exactly one candle on it, and there are no left-over pieces. For that, he made mm cuts across the cake. Could you help check if John’s cuts successfully divide the candles on the cake?

Formally, the cake is a circle of radius rr centered at (0,0)(0,0). The candles are nndistinct points located strictly inside the circle. Each cut is a straight line ax+by+c=0ax+by+c=0, described by three coefficients aa, bb, and cc.

Input

Input starts with three integers nn (1≤n≤501≤n≤50), mm (1≤m≤151≤m≤15), and rr (1≤r≤1001≤r≤100) on the first line.

The next nn lines give the locations of the candles. Each line has two integers xx and yy giving the coordinates of one candle (0≤x2+y2−−−−−−√<r0≤x2+y2<r).

The next mm lines give the coefficients of the cutting lines. Each line has three integers aa, bb, and cc (0≤|a|,|b|≤100,0≤|c|≤200000≤|a|,|b|≤100,0≤|c|≤20000) describing a line of the form ax+by+c=0ax+by+c=0. The values aa and bb are not both zero.

All candles and lines are distinct. No candle is on a cut line. No line is completely outside or tangent to the cake. The input guarantees that the number of cake pieces remains the same if any cut line is shifted by at most 10−410−4 in any direction. The input also guarantees that each candle remains in the interior of the same piece of cake if its position is shifted by at most 10−410−4 in any direction.

Output

Output “yes” if John’s cuts successfully divide the cake so that each piece he obtains has exactly one candle on it. Otherwise, output “no”.

Sample Input 1 Sample Output 1
4 2 3
0 1
1 0
-1 0
0 -1
-1 1 0
2 1 0
yes
Sample Input 2 Sample Output 2
4 3 3
0 1
1 2
-1 2
0 -1
-1 1 -2
-1 -1 2
0 -1 0
no
Sample Input 3 Sample Output 3
3 2 3
2 1
0 0
-1 -2
1 1 -2
3 6 12
yes
Sample Input 4 Sample Output 4
3 1 2
0 0
-1 1
1 -1
-2 2 1
no

 

題意:給出一個蛋糕 即圓心爲(0,0)半徑爲 r 的一個圓,上面有 n 塊糖果 ( x , y ) 爲糖果點的座標 ,切 m 刀 直線方程 ax+by+c,問是否能恰好將這 n 塊糖果分在 n 個不同的區域上

我們可以先判斷糖果是否是在不同的區域上,然後再判斷區域數是否是 n。

先行知識:

1.把點(x,y)帶入直線方程ax+by+c,有三種狀態>0,=0,<0,可以判斷點在直線的左邊,線上,右邊三種狀態。

只要有一條線使兩個點在這條線的不同側,這兩個點就已經在不同區域

2.圓內的點、邊、區域數的關係 v + e + 1 = n,v是交點數,e爲邊數,n是區域數

3.一般式方程兩直線相交,a1*b2! = a2b1,如果相等的話a1*b2! = a2b1,即a1/a2 = b1/b2兩直線平行

兩直線交點:

x = (b1*c2-b2*c1)/D

y = (c1*a2-c2*a1)/D

D = a0*b1 – a1*b0, (D爲0時,表示兩直線重合)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <map>
#include <set>
using namespace std;
const int maxn = 100 + 7 ;
typedef pair<double,double> point;//直線的交點
bool k[maxn][maxn];//判斷點i在直線j的哪一側
struct Point
{
    int x,y;
}p[maxn];
struct Line
{
    int a,b,c;
}l[maxn];
int main()
{
    int n,m,r;
    cin>>n>>m>>r;
    for(int i=1;i<=n;i++)
        cin>>p[i].x>>p[i].y;
    for(int i=1;i<=m;i++)
        cin>>l[i].a>>l[i].b>>l[i].c;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(p[i].x*l[j].a+p[i].y*l[j].b+l[j].c>0)
                k[i][j] = true;//點在線的哪一側,不能在直線上
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j)
                continue;
            bool flag = false;
            for(int h=1;h<=m;h++)
            {
                if(k[i][h]!=k[j][h])//只要有一條線使兩個點在不同側 就已經在不同區域
                {
                    flag = true;
                    break;
                }
            }
            if(!flag)
            {
                cout<<"no"<<endl;
                return 0;
            }
        }
    }
    set<point>pp;
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(i==j)
                continue;
            int a1=l[i].a,b1=l[i].b,c1=l[i].c;
            int a2=l[j].a,b2=l[j].b,c2=l[j].c;
            double d=a1*b2-a2*b1;
            if(a2*b1-a1*b2!=0)//兩直線相交
            {
                double x = 1.0*(b1*c2-b2*c1)/d;
                double y = 1.0*(c1*a2-c2*a1)/d;
                if(x*x+y*y<r*r)//圓心(0,0),如果交點在圓內
                    pp.insert(point(x,y));//防止交點重複 去重
            }
        }
    }
    if(pp.size()+m+1==n) //V+E+1=N 區域數是否爲n
        cout<<"yes"<<endl;
    else
        cout<<"no"<<endl;
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章