二维平面上的二分类问题:直线分类器
在机器学习中,分类问题是一个常见的任务。今天,我们来探讨一个简单的二分类问题:在二维平面上,如何用一条直线将两类点完美分隔开来。这个问题不仅是一个有趣的数学问题,也是理解更复杂分类算法的基础。
问题描述
给定平面上的 n 个点,每个点都有一个类别(A 或 B)。我们需要找到一条直线,使得这条直线能够将所有 A 类点和 B 类点完全分隔到两侧。对于给定的 m 条直线,我们需要判断每条直线是否满足这个条件。
输入格式
输入包含 n+m+1 行:
-
第一行包含两个正整数 n 和 m,分别表示点的数量和查询的数量。
-
接下来的 n 行,每行包含三个值:点的横坐标 xi、纵坐标 yi 和类别 typei。
-
接下来的 m 行,每行包含三个整数 θ0、θ1 和 θ2,表示一条直线的参数。
输出格式
对于每个查询,输出 "Yes" 或 "No",表示该直线是否能完美分隔两类点。
解题思路
1. 理解直线方程
一条直线可以用方程 θ0+θ1x+θ2y=0 表示。对于平面上的任意一点 (x,y),代入方程后:
-
如果结果大于 0,点在直线的一侧;
-
如果结果小于 0,点在直线的另一侧;
-
如果等于 0,点在直线上(但题目保证不会有这种情况)。
2. 判断点的位置
对于每个查询的直线,我们需要计算每个点相对于这条直线的位置。具体来说:
-
对于每个点 (xi,yi),计算 θ0+θ1xi+θ2yi 的值。
-
如果这个值大于 0,我们认为这个点在直线的一侧;
-
如果小于 0,则在另一侧。
3. 检查分类情况
我们需要确保:
-
所有 A 类点都在直线的一侧;
-
所有 B 类点都在直线的另一侧。
具体步骤如下:
-
将所有 A 类点和 B 类点分别存储。
-
对于每个查询的直线:
-
计算所有 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 类点完美分隔。
总结
这个问题通过简单的数学计算和集合操作,判断一条直线是否能完美分隔两类点。这种思路是许多机器学习算法(如支持向量机)的基础。虽然这个问题相对简单,但它帮助我们理解了分类问题的核心思想:找到一个决策边界,将不同类别的数据分开。