C++求解:平面上有n个点,问总共可以组成多少条直线

思路

对输入的点,两两组合求取斜率,这样可能会出现某一斜率对应多对点。然后对属于同一斜率的多对点,当成一幅图,求取连通分支个数

这里对对属于同一斜率的多对点,当成一幅图,求取连通分支个数解释一下:
假设对于斜率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 dot1,另一个点存在vector dot2。value就是对应的斜率值。
对于输入:
vector points;来保存输入的点。
vectorslopes;来保存总共可以有多少个斜率。
对于每一个斜率,求取连通分支个数:

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, vectorB)
{
    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;
    vectorslopes;
    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)
            {
                vectordot1; dot1.push_back(points[i]);
                vectordot2; 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)//出现新的斜率
                {
                    vectordot1; dot1.push_back(points[i]);
                    vectordot2; 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;
}

你可能感兴趣的:(数据结构)