zoukankan      html  css  js  c++  java
  • 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
    */
  • 相关阅读:
    jQuery之概念以及基本使用
    微信小程序开发(八)-生命周期
    微信小程序开发(七)-自定义组件
    微信小程序开发(六)-常⻅组件
    微信小程序开发(五)-⼩程序事件的绑定与样式
    微信小程序开发(四)-列表渲染
    微信小程序开发(三)-数据绑定
    vue中使用v-echars
    原生aspx页面如何引用公共js和css
    layui常用的验证
  • 原文地址:https://www.cnblogs.com/a249189046/p/7458607.html
Copyright © 2011-2022 走看看