hdu-1558-Segment set(计算几何&并查集)

Problem Description

A segment and all segments which are connected with it compose a segment set. The size of a segment set is the number of segments in it. The problem is to find the size of some segment set.
hdu-1558-Segment set(计算几何&并查集)_第1张图片

Input

In the first line there is an integer t - the number of test case. For each test case in first line there is an integer n (n<=1000) - the number of commands.
There are two different commands described in different format shown below:
P x1 y1 x2 y2 - paint a segment whose coordinates of the two endpoints are (x1,y1),(x2,y2).
Q k - query the size of the segment set which contains the k-th segment.
k is between 1 and the number of segments in the moment. There is no segment in the plane at first, so the first command is always a P-command.

Output

For each Q-command, output the answer. There is a blank line between test cases.

Sample Input

1
10
P 1.00 1.00 4.00 2.00
P 1.00 -2.00 8.00 4.00
Q 1
P 2.00 3.00 3.00 1.00
Q 1
Q 3
P 1.00 4.00 8.00 2.00
Q 2
P 3.00 3.00 6.00 -2.00
Q 5

Sample Output

1
2
2
2
5

这道题是并查集的简单应用。难点是如何判断两条线段是不是相交(详情在这里)。
我使用的是直接计算两条直线的交点,然后再判断交点是不是在直线上
代码如下:

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#define N 1010
const int mm = 1000000007;
using namespace std;
struct line
{
    double x1, y1, x2, y2;
    bool fun(line l)
    {
        double xx, yy;  //两直线的交点 
        double k1, k2;  //两直线的斜率 
        if (fabs(this->x1-this->x2) < 1e-7 && fabs(l.x1-l.x2) < 1e-7)   //都垂直于y轴 
        {
            if (fabs(l.x1-this->x1) < 1e-7)     return true;
            return false;
        }
        else if (fabs(this->x1-this->x2) < 1e-7)    //
        {
            if ((this->x1-l.x1)*(this->x1-l.x2) > -1e-8)    return false;
            k2 = (l.y1-l.y2)/(l.x1-l.x2);
            xx = this->x1;
            yy = k2*(xx-l.x1) + l.y1;
            if ((this->y1-yy)*(yy-this->y2) >= -1e-8)   return true;
            return false;
        }
        else if (fabs(l.x1-l.x2) < 1e-7)    //l垂直于y轴 
        {
            if ((l.x1-this->x1)*(l.x1-this->x2) > -1e-8)    return false;
            xx = l.x1;
            yy = k1*(xx-this->x1) + this->y1;
            if ((l.y1-yy)*(yy-l.y2) >= 0)   return true;
            return false;
        }
        else
        {
            k1 = (this->y1-this->y2)/(this->x1-this->x2);
            k2 = (l.y1-l.y2)/(l.x1-l.x2);
            if (fabs(k1-k2) < 1e-7)     return false;   // 两直线是不是平行 
            xx = (k1*this->x1-this->y1-k2*l.x1+l.y1)/(k1-k2);
            yy = k2*(xx-l.x1) + l.y1;
            if ((this->x1-xx)*(xx-this->x2)>=0 && (l.x1-xx)*(xx-l.x2)>=0)   return true;//两直线的交点是不是在两条连段上 
            return false;
        }
    }
}ll[N];
int father[N], num[N];
int find(int x)
{
    if (x == father[x]) return father[x];
    int t = father[x];
    father[x] = find(father[x]);
    num[x] += num[t];
    return father[x];
}
void union_set(int x, int y)
{
    int xx = find(x);
    int yy = find(y);
    if (xx != yy)
    {
        father[xx] = yy;
        num[yy] += num[xx];
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("1.txt", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    int i, j, T, n, cnt, t;
    char c;
    cin >> T;
    while(T--)
    {
        cin >> n;
        cnt = 1;
        for (i = 0; i <= n; i++)
        {
            father[i] = i;
            num[i] = 1;
        }
        while(n--)
        {
            cin >> c;
            if (c == 'P')
            {
                cin >> ll[cnt].x1 >> ll[cnt].y1 >> ll[cnt].x2 >> ll[cnt].y2;
                for (i = 1; i < cnt; i++)
                    if (ll[cnt].fun(ll[i]))
                        union_set(i, cnt);
                cnt++;
            }
            else
            {
                cin >> t;
                t = find(t);
                cout << num[t] << endl;
            }
        }
        if (T)  cout << endl;
    }
    return 0;
}

你可能感兴趣的:(hdu-1558-Segment set(计算几何&并查集))