hrbust 1382 Split the Points【判断正方形+判断矩形+极角排序】

本文介绍了一种通过暴力枚举的方式解决特定点集划分问题的方法,即从八个给定点中找出能构成正方形和矩形的两组各四个点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Split the Points

Time Limit: 1000 MS

Memory Limit: 65536 K

 

Total Submit: 26(8 users)

Total Accepted: 10(7 users)

Rating: 

Special Judge: No

 

Description

There are eight distinct points on the plane.

Leyni wonders if he can split the points into two sets each containing four points so that the points from one of the sets form a square and the others form a rectangle.

Help him solve this problem.

Input

There are multiple test cases. The first line of input is an integer T indicating the number of test cases. Then T test cases follow.

For each test case:

Line 1..8. Each line contains two integer xiyi(-104 ≤ xi, yi ≤ 104) indicating the coordinate of a point.

Output

For each test case:

Line 1. Output "YES" if Leyni can split the points as he desires, otherwise output "NO".

Sample Input

3

0 0

10 11

10 0

0 11

1 1

2 2

2 1

1 2

0 0

1 1

2 2

3 3

4 4

5 5

6 6

7 7

0 0

4 4

4 0

0 4

1 2

2 3

3 2

2 1

Sample Output

YES

NO

YES

Source

哈理工2012春季校赛 - 现场赛(热身)

Author

齐达拉图@HRBUST

 

题目大意:


一共t组数据,对于每组数据给出8个点,我们的任务是将这8个点分成两组,一组包含四个点,第一组的四个点要求组成一个正方形,第二个组的四个点要求组成一个矩形,问是否能够分成这样的两组。


思路:


1、首先这里分析一下时限问题,一共八个点,我们直接暴力找一个正方形的话,是需要8*8*8*8的复杂度进行枚举,然后再进行各种操作,也并不是很高,所以我们这里就不需要技巧优化分组问题了,直接先找到一个正方形之后判断剩下四个点能否组成矩形即可。


2、正方形的判断:枚举出4个点之后,求出其能够组合出来的六条边的边长,然后进行排序,得到升序的一个数组dis【】,如果dis【0-3】相等。dis【4-5】也相等,并且dis【0】*dis【0】*2==dis【5】*dis【5】,那么就能够判断这个四边形一定是正方形。(满足四条临边相等,并且满足有一个直角)


3、然后剩下四个点,我们要判断他是不是一个矩形,我们先进行一次极角排序,得到一个有序的四个点,而且我们知道,排序结束的点,p0,p2是对顶角。p1,p3是对顶角,我们用向量判断对边平行,然后一条临边垂直即可。(平行四边形的基础上加一个直角)。



AC代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct point
{
    int x,y;
}p[10];
int x[10];
int y[10];
int vis[10];
int cross(point a, point b, point c)
{
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
int dis(point a)
{
    return (a.x-p[0].x)*(a.x-p[0].x)+(a.y-p[0].y)*(a.y-p[0].y);
}
int cmp(point a, point b)//极角排序、
{
    if(cross(p[0], a, b) > 0||(cross(p[0], a, b)==0&&dis(a) < dis(b)))
        return 1;
    return 0;
}
int Slove(int one,int two,int three,int four)//判断矩形
{
    vis[one]=1;vis[two]=1;vis[three]=1;vis[four]=1;
    int cont=0;
    for(int i=0;i<8;i++)
    {
        if(vis[i]==0)
        {
            p[cont].x=x[i];
            p[cont++].y=y[i];
        }
    }
    sort(p,p+cont,cmp);
    if(p[0].x-p[1].x==p[3].x-p[2].x&&p[0].y-p[1].y==p[3].y-p[2].y)
    {
        if(p[2].x-p[1].x==p[3].x-p[0].x&&p[2].y-p[1].y==p[3].y-p[0].y)
        {
            if((p[1].x-p[2].x)*(p[2].x-p[3].x)+(p[1].y-p[2].y)*(p[2].y-p[3].y)==0)
            {
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        for(int i=0;i<8;i++)
        {
            scanf("%d%d",&x[i],&y[i]);
        }
        int flag=0;
        for(int i=0;i<8;i++)
        {
            for(int j=i+1;j<8;j++)
            {
                for(int k=j+1;k<8;k++)
                {
                    for(int l=k+1;l<8;l++)//暴力枚举4个点出来
                    {
                        memset(vis,0,sizeof(vis));
                        p[0].x=x[i];p[0].y=y[i];
                        p[1].x=x[j];p[1].y=y[j];
                        p[2].x=x[k];p[2].y=y[k];
                        p[3].x=x[l];p[3].y=y[l];
                        long long int dis[10];
                        int cont=0;
                        for(int z=0;z<4;z++)
                        {
                            for(int zz=z+1;zz<4;zz++)
                            {
                                dis[cont++]=(p[z].x-p[zz].x)*(p[z].x-p[zz].x)+(p[z].y-p[zz].y)*(p[z].y-p[zz].y);
                            }
                        }
                        sort(dis,dis+cont);
                        if(dis[0]==dis[1]&&dis[1]==dis[2]&&dis[2]==dis[3]&&dis[4]==dis[5]&&dis[0]*2==dis[5])//先判断是不是正方形
                        {
                            int tt=Slove(i,j,k,l);//然后判断剩下的四个点能否组成矩形
                            if(tt==1)flag=1;
                        }
                    }
                }
            }
        }
        if(flag==1)printf("YES\n");
        else printf("NO\n");
    }
}
/*
50
10000 10000
-10000 10000
10000 -10000
-10000 -10000
1 1
2 2
3 3
4 4
10000 10000
-10000 10000
10000 -10000
-10000 -10000
9999 9999
-9999 9999
9999 -9999
-9999 -9999
0 2
0 0
1 2
1 0
4 2
4 0
10 2
10 0
10000 10000
-10000 10000
10000 -10000
-10000 -10000
-1 0
0 0
1 0
0 1
*/







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值