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 1Sample Output 1
4 2 3
0 1
1 0
-1 0
0 -1
-1 1 0
2 1 0
yes
Sample Input 2Sample 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 3Sample Output 3
3 2 3
2 1
0 0
-1 -2
1 1 -2
3 6 12
yes
Sample Input 4Sample 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;
}

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值