A - Birthday Cake VJ(计算几何 平面欧拉)

博客围绕生日蛋糕分割问题展开,要将有n个蜡烛的蛋糕用m条直线分割成n块,每块有一个蜡烛。给出输入输出格式及示例,还提及前置技能平面欧拉公式V - E + F = 1,作者学习新函数简化程序,解题过程经历多次错误后成功。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A - Birthday Cake
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 nn distinct 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

前置技能 : 平面欧拉公式
于是有一个平面的欧拉公式(最后我没想起来)

V-E+F = 2

V是点数,E是边数,F是面数(也就是这里的块数),考虑在圆形中,所以

V-E+F=1

易知F = n

V是园内交点数,易知对于每一条直线来说,如果有k个交点,会被分成k+1条边
学习了几个新的函数来简化程序。(后面补充)

PS 因为近期学的计算机底层的东西多一些然后想到了几个逻辑运算符号来解决输出的问题
心路历程: 一开始感觉是数学方面的,然后感觉应该能做, 2 发 WA, 2 发 RE, 感觉还是能做,然后一血。。。。。。。。。。。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10005;
int a[maxn];
int b[maxn];
int c[maxn];
bool vis[maxn][maxn];
pair<int,int> d[maxn];
int n,m,r;
int main()
{
    for(int i = 0; i < maxn; i++)
        for(int j = 0; j < maxn; j++)
            vis[i][j] = 1;
    scanf("%d %d %d",&n,&m,&r);
    for(int i = 0; i<n; i++)
        scanf("%d%d",&d[i].first,&d[i].second);
    for(int i = 0; i<m; i++)
    {
        bool t[maxn] = {0};
        scanf("%d %d %d",&a[i],&b[i],&c[i]);
        for(int j=0; j<n; j++)
            if(a[i]*d[j].first + b[i]*d[j].second + c[i]<0)t[j] = 1;
        for(int j = 0; j < n; j++)
            if(t[j])
                for(int k = 0; k < n; k++)
                    if(!t[k])
                    {
                        vis[k][j] = 0;
                        vis[j][k] = vis[k][j];
                    }
    }
    for(int i=0; i<n; i++)
    {
        int cnt = 0;
        for(int j=0; j<n; j++)
            if(vis[i][j])cnt++;
        if(cnt>1)
           return 0&printf("no\n");
    }
    int v = 0,e = 0;
    for(int i = 0; i < m; i++)
    {
        int cnt = 0;
        for(int j = 0; j < m; j++)
            if(i!=j)
            {
                if(a[i]*b[j] == a[j]*b[i])
                    continue;
                double y = -1.0*(a[j] * c[i] - a[i] * c[j])/(a[j] * b[i] - a[i] * b[j]);
                double x = 1.0*(b[i] * c[j] - b[j] * c[i])/(a[i] * b[j] - a[j] * b[i]);
                if(x * x + y * y < r * r)
                    cnt++;
            }
        v += cnt;
        e += cnt + 1;
    }
    v /= 2;
    if(v - e + n != 1)
      return 0&printf("no\n");

    printf("yes\n");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值