CCF-CSP认证练习题-第19次-线性分类器

二维平面上的二分类问题:直线分类器

在机器学习中,分类问题是一个常见的任务。今天,我们来探讨一个简单的二分类问题:在二维平面上,如何用一条直线将两类点完美分隔开来。这个问题不仅是一个有趣的数学问题,也是理解更复杂分类算法的基础。

问题描述

给定平面上的 n 个点,每个点都有一个类别(A 或 B)。我们需要找到一条直线,使得这条直线能够将所有 A 类点和 B 类点完全分隔到两侧。对于给定的 m 条直线,我们需要判断每条直线是否满足这个条件。

输入格式

输入包含 n+m+1 行:

  • 第一行包含两个正整数 n 和 m,分别表示点的数量和查询的数量。

  • 接下来的 n 行,每行包含三个值:点的横坐标 xi​、纵坐标 yi​ 和类别 typei​。

  • 接下来的 m 行,每行包含三个整数 θ0​、θ1​ 和 θ2​,表示一条直线的参数。

输出格式

对于每个查询,输出 "Yes" 或 "No",表示该直线是否能完美分隔两类点。

解题思路

1. 理解直线方程

一条直线可以用方程 θ0​+θ1​x+θ2​y=0 表示。对于平面上的任意一点 (x,y),代入方程后:

  • 如果结果大于 0,点在直线的一侧;

  • 如果结果小于 0,点在直线的另一侧;

  • 如果等于 0,点在直线上(但题目保证不会有这种情况)。

2. 判断点的位置

对于每个查询的直线,我们需要计算每个点相对于这条直线的位置。具体来说:

  • 对于每个点 (xi​,yi​),计算 θ0​+θ1​xi​+θ2​yi​ 的值。

  • 如果这个值大于 0,我们认为这个点在直线的一侧;

  • 如果小于 0,则在另一侧。

3. 检查分类情况

我们需要确保:

  • 所有 A 类点都在直线的一侧;

  • 所有 B 类点都在直线的另一侧。

具体步骤如下:

  1. 将所有 A 类点和 B 类点分别存储。

  2. 对于每个查询的直线:

    • 计算所有 A 类点的值,记录它们的符号(正或负)。

    • 计算所有 B 类点的值,记录它们的符号。

    • 如果所有 A 类点的符号相同,且所有 B 类点的符号也相同,并且两者的符号相反,则这条直线可以完美分隔两类点。

代码实现

以下是使用 C++ 实现的代码:

#include <iostream>
#include <vector>
#include <set>
using namespace std;

struct Point {
    int x, y;
    char type;
};

int main() {
    int n, m;
    cin >> n >> m;

    vector<Point> points(n);
    set<char> types;

    // 读取点
    for (int i = 0; i < n; i++) {
        cin >> points[i].x >> points[i].y >> points[i].type;
        types.insert(points[i].type);
    }

    // 处理每个查询
    for (int i = 0; i < m; i++) {
        int theta0, theta1, theta2;
        cin >> theta0 >> theta1 >> theta2;

        set<char> leftTypes, rightTypes;

        for (const auto& p : points) {
            long long val = (long long)theta0 + (long long)theta1 * p.x + (long long)theta2 * p.y;

            if (val > 0) {
                rightTypes.insert(p.type);
            } else if (val < 0) {
                leftTypes.insert(p.type);
            }
        }

        // 检查是否完美分隔
        bool valid = false;
        if (leftTypes.size() == 1 && rightTypes.size() == 1 && *leftTypes.begin() != *rightTypes.begin()) {
            valid = true;
        } else if ((leftTypes.empty() && rightTypes.size() == 1) || (rightTypes.empty() && leftTypes.size() == 1)) {
            valid = true;
        }

        cout << (valid ? "Yes" : "No") << endl;
    }

    return 0;
}

样例输入与输出

输入样例

9 3
1 1 A
1 0 A
1 -1 A
2 2 B
2 3 B
0 1 A
3 1 B
1 3 B
2 0 A
0 2 -3
-3 0 2
-3 1 1

输出样例

No
No
Yes

样例解释

只有第三个查询的直线能够将 A 类和 B 类点完美分隔。

总结

这个问题通过简单的数学计算和集合操作,判断一条直线是否能完美分隔两类点。这种思路是许多机器学习算法(如支持向量机)的基础。虽然这个问题相对简单,但它帮助我们理解了分类问题的核心思想:找到一个决策边界,将不同类别的数据分开。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值