对输入的点,两两组合求取斜率,这样可能会出现某一斜率对应多对点。然后对属于同一斜率的多对点,当成一幅图,求取连通分支个数。
这里对对属于同一斜率的多对点,当成一幅图,求取连通分支个数解释一下:
假设对于斜率k=1.0,有点对
(1,1) ,(2,2)
(2,2),(3,3)
(3,3,),(1,1)
(4,3),(3,2)
那么实际上只有两条直线,(1,1),(2,2),(3,3)是连在一起的,(4,3),(3,2)是连在一起的。其实就是对应两个连通的分支。
求取连通分支,可以利用并查集。
代码思路解析:
首先定义两个结构体
point和slope,point对应平面上的坐标值,其中ID是给一个点标号,这里是为了在并查集中求取连通分支用。
slope是对应于某一斜率,它所包含的点对。其中每一对的一个点存在vector
,另一个点存在vector
。value就是对应的斜率值。
对于输入:
用vector
来保存输入的点。
用vector
来保存总共可以有多少个斜率。
对于每一个斜率,求取连通分支个数:
for (int i = 0; i < len; i++)
count = count + CalConnectArea(slopes[i].dot1, slopes[i].dot2);//计算每个斜率对应的连通分支个数
返回count
就是最终的直线数。
写到这,有一股好熟悉的节奏。。。。。。
#include
#include
#include
#define sigma 0.0001
#define slope_max 10000//斜率无穷大定义为10000
using namespace std;
struct point
{
double x;
double y;
int ID;//给每个点标号
point(int x1, int y1,int ID=0) :x(x1), y(y1),ID(ID) {};
bool operator==(const point b) const
{
return (abs(this->x - b.x)abs(this->y == b.y)struct slope//定义斜率和两个直线
{
vector dot1;//斜率有两个点确定,第一个点的坐标集合
vector dot2;//第二个点的坐标集合,个数和第一个一样
double value;
slope(vector dot1_1, vector dot2_2, double value) :dot1(dot1_1), dot2(dot2_2), value(value) {};
};
int find(int x,int *pre)
{
int r = x;
while (r != pre[r])
r = pre[r];
int i=x, j;
while (pre[i] != r)//路径压缩
{
j = pre[i];
pre[i] = r;
i = j;
}
return r;
}
void join(int x, int y, int *pre)
{
int rx = find(x, pre), ry = find(y, pre);
if (rx != ry)
pre[ry] = rx;
}
int CalConnectArea(vector A, vector B)
{
int n = A.size();
int *num1 = new int[n];
int *num2 = new int[n];
int index = 1;
vector temp;
for (int i = 0; i < n; i++)//求num1
{
if (temp.size() == 0)
{
temp.push_back(point(A[i].x, A[i].y, index));
num1[i] = index;
index++;
}
else
{
vector ::iterator it;
it = find(temp.begin(), temp.end(), A[i]);
/*cout << ((*it) == B[i]) << endl;*/
if (it != temp.end())
{
num1[i] = (*it).ID;
}
else
{
temp.push_back(point(B[i].x, A[i].y, index));
num1[i] = index;
index++;
}
}
}
for (int i = 0; i < n; i++)//求num2
{
if (temp.size() == 0)
{
temp.push_back(point(B[i].x, B[i].y, index));
num2[i] = index;
index++;
}
else
{
vector ::iterator it;
it = find(temp.begin(), temp.end(), B[i]);
if (it != temp.end())
{
num2[i] = (*it).ID;
}
else
{
temp.push_back(point(A[i].x, B[i].y, index));
num2[i] = index;
index++;
}
}
}
//总共index-1个点,看计算有多少个连通分支
int *pre = new int[index];
bool *t = new bool[index];
//利用并查集
for (int i = 1; i < index; i++)//初始化
{
pre[i] = i;
t[i] = false;
}
for (int i = 0; i < n; i++)
{
join(num1[i], num2[i], pre);
}
for (int i = 1; i 1;
int count = 0;
for (int i = 1; i < index; i++)
if (t[i])
count++;
return count;
}
int main()
{
ifstream in("data.txt");
int N;//点数
in >> N;
vector points;
int x, y;
for (int i = 0; i < N; i++)
{
in >> x >> y;
points.push_back(point(x, y));
}
cout << "输入的点个数" << N << "它们的坐标分别是"<for (int i = 0; i < N; i++)
{
cout << points[i].x << " " << points[i].y << endl;
}
//对每一个点,求取它与所有直线的斜率
double slope_value = 0.0;
vector slopes;
bool flag = true;
for (int i = 0; i < N; i++)
for (int j = i + 1; j < N; j++)
{
if (points[i].x == points[j].x)
slope_value = slope_max;
else
slope_value = (points[j].y - points[i].y) / (points[j].x - points[i].x);
int slope_num = slopes.size();
if (slope_num == 0)
{
vector dot1; dot1.push_back(points[i]);
vector dot2; dot2.push_back(points[j]);
slopes.push_back(slope(dot1, dot2, slope_value));
}
else
{
flag = true;
for (int k = 0; k < slope_num; k++)
{
if (abs(slopes[k].value - slope_value) < sigma)//存在相同的斜率
{
slopes[k].dot1.push_back(points[i]);
slopes[k].dot2.push_back(points[j]);
flag = false;
break;
}
}
if (flag)//出现新的斜率
{
vector dot1; dot1.push_back(points[i]);
vector dot2; dot2.push_back(points[j]);
slopes.push_back(slope(dot1, dot2, slope_value));
}
}
}
//slopes现在存放了所有的斜率
int len = slopes.size();//不同斜率个数
int count = 0;
for (int i = 0; i < len; i++)
count = count + CalConnectArea(slopes[i].dot1, slopes[i].dot2);//计算每个斜率对应的连通分支个数
cout << "总共可以组成直线数" << endl;
cout << count << endl;
return 0;
}