• 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
    */
  • 相关阅读:
    C语言-if语句
    C语言-表达式
    C语言-基础
    Java for LeetCode 187 Repeated DNA Sequences
    Java for LeetCode 179 Largest Number
    Java for LeetCode 174 Dungeon Game
    Java for LeetCode 173 Binary Search Tree Iterator
    Java for LeetCode 172 Factorial Trailing Zeroes
    Java for LeetCode 171 Excel Sheet Column Number
    Java for LeetCode 169 Majority Element
  • 原文地址:https://www.cnblogs.com/a249189046/p/7458607.html
Copyright © 2020-2023  润新知