FJUT 2351 T^T的图论(并查集)

T^T的图论

TimeLimit:3000MS  MemoryLimit:256MB
64-bit integer IO format:%lld
已解决 | 点击收藏
Problem Description

有一个坐标系,坐标系上有n个点,在同一行或同一列上的任意两点称为关联的,并且关联属性是可传递的,即A和B关联,B和C关联,则可认为A和C关联,现在问图中是否任意两点都是关联的。

Input

n>=2 && n<=50万

每个点的坐标x、y满足 1<=x、y<=50000

Output

如果是关联的,输出YES,否则,输出NO

SampleInput
NO
YES

分析:根据题目我们需要把具有x和y任选其一相同的,合并在一个集合中
一开始想的是先把所有的点按x的大小进行排序,相同的点合并到一个集合中
再把所有的点按y的大小进行排序,相同的点合并道一个集合中
这样的话刚刚可以在时间限制内卡过去 2900多MS

代码如下:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <vector>
#include <stack>
using namespace std;
const int MAXN=5e5+10;
int pre[MAXN];
int num[MAXN];
struct node
{
    int x;
    int y;
    int id;
}poi[MAXN];
int cmp1(node a,node b)
{
    return a.x<b.x;
}
int cmp2(node a,node b)
{
    return a.y<b.y;
}
int Find(int x)
{
    int h,tem;
    h=x;
    while(x!=pre[x])
        x=pre[x];
    while(h!=x)
    {
        tem=pre[h];
        pre[h]=x;
        h=tem;
    }
    return x;
}
void join(int x,int y)
{
    int p=Find(x);
    int q=Find(y);
    if(p!=q)
    {
        pre[p]=q;
        num[q]=num[p]+num[q];
    }
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++){
        pre[i]=i;
        num[i]=1;
        }
       for(int i=0;i<n;i++)
       {
           scanf("%d%d",&poi[i].x,&poi[i].y);
           poi[i].id=i;
       }
       sort(poi,poi+n,cmp1);
       for(int i=1;i<n;i++)
       {
         if(poi[i].x==poi[i-1].x)
            join(poi[i-1].id,poi[i].id);
       }
       sort(poi,poi+n,cmp2);
       for(int i=1;i<n;i++)
       {
         if(poi[i].y==poi[i-1].y)
           join(poi[i-1].id,poi[i].id);
       }
       if(num[Find(0)]==n)puts("YES");
       else puts("NO");
    }
    return 0;
}

 看了其他人的代码后发现,可以先对于x的话,统计集合的数量,如果这个x值第一次出现,那么集合必增加。如果已经出现过,那么就能合并到已经出现的集合里面

然后将y排序,y值相同的点,再去看它们的x值是否已经合并到了一个集合,如果不在一个集合,就将它们合并到一个集合里,并且集合的数量减一.

(在这里,我们是根据x的值进行并查集,那么一个开始x值相同的就自动到了一个集合,这种方法可以减少进行集合合并的次数,并节约时间)

代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <vector>
#include <stack>
using namespace std;
const int MAXN=5e5+10;
int pre[MAXN];
int ans;
int vis[MAXN];
struct node
{
    int x;
    int y;
    int id;
}poi[MAXN];
int cmp1(node a,node b)
{
    return a.x<b.x;
}
int cmp2(node a,node b)
{
    return a.y<b.y;
}
int Find(int x)
{
    int h,tem;
    h=x;
    while(x!=pre[x])
        x=pre[x];
    while(h!=x)
    {
        tem=pre[h];
        pre[h]=x;
        h=tem;
    }
    return x;
}
void join(int x,int y)
{
    int p=Find(x);
    int q=Find(y);
    if(p!=q)
    {
        pre[p]=q;
        ans--;
    }
}
int main()
{
    int n,x1,x2;
    while(scanf("%d",&n)!=EOF)
    {
        memset(vis,0,sizeof(vis));
      for(int i=1;i<=50000;i++)
        pre[i]=i;
      ans=0;
      for(int i=0;i<n;i++)
        scanf("%d%d",&poi[i].x,&poi[i].y);
      for(int i=0;i<n;i++)
      {
          if(!vis[poi[i].x])
          {
              vis[poi[i].x]=1;
              ans++;
          }
      }
      sort(poi,poi+n,cmp2);
      for(int i=1;i<n;i++)
      {
          if(poi[i].y==poi[i-1].y)
          {
              join(poi[i].x,poi[i-1].x);
          }
      }
      if(ans>1)puts("NO");
      else puts("YES");
    }
    return 0;
}
/*4
1 3
4 5
5 3
4 3
NO
*/
原文地址:https://www.cnblogs.com/a249189046/p/7458607.html