zoukankan      html  css  js  c++  java
  • UOJ #142. 【UER #5】万圣节的南瓜灯 并查集

    #142. 【UER #5】万圣节的南瓜灯

    Time Limit: 20 Sec

    Memory Limit: 256 MB

    题目连接

    http://uoj.ac/problem/142

    Description

    红包是一个心灵手巧的男孩子。今天是万圣节,红包正在家里制作南瓜灯。

    这时候一群熊孩子们敲开了红包家的门,他们高呼着“不用给糖,只要捣蛋”的口号把红包的南瓜灯弄坏了。这让红包很难过,于是他打算把这些被弄坏的南瓜灯做成其他的工艺品。

    红包把它的南瓜灯划分成了 n×m 的网格,并用 (x,y) 表示第 x 行,第 y 列的格子。两个格子是相邻的当且仅当它们有一条公共边,特殊地, (x,1) 和 (x,m) 红包也视为是相邻的,但是他不把 (1,x) 和 (n,x) 当做是相邻的。

    对于一个有 K 个格子被弄坏的南瓜灯,如果它能被制作成工艺品,当且仅当对于任意两个没有被弄坏的格子,都存在且仅存在一条连接它们的简单路径。一条简单路径定义为一个只包含没有被弄坏的格子的序列 A1 至 An ,其中对于任意的 1≤i<n 都有 Ai 和 Ai+1 是相邻的,且每一个格子在序列中至多出现了一次。

    现在红包有 T 个南瓜灯,他想让你帮他分别判断每一个南瓜灯能不能被做成工艺品。

    Input

    第一行一个正整数 T,表示南瓜灯数目。

    对于每一个南瓜灯,第一行是三个整数 n,m,K,表示南瓜灯的大小和被弄坏的格子数。

    接下来 K 行每行包含两个整数 x,y(1≤x≤n,1≤y≤m),表示第 x 行第 y 列的格子被弄坏了。

    数据保证 n,m≥3,0≤K<nm 且不会重复描述一个被弄坏的格子。

    Output

    对于每一个南瓜灯,输出一行,如果这个南瓜灯能被做成工艺品,那么输出 "Yes",否则输出 "No"。

    Sample Input

    3
    3 3 4
    2 1
    2 3
    3 1
    3 3
    3 3 5
    1 1
    1 2
    2 1
    3 1
    3 2
    3 3 4
    1 1
    2 2
    2 3
    3 3

    Sample Output

    No
    Yes
    No

    HINT

    题意

     给你一个网格,然后有些地方是墙,然后问你空出来的地方,是否能够构成一颗树

    注意,左右是相连的

    题解:

    就暴力就好了,注意如果n*m>3e5 是可以直接判断为no的

    所以这个可以拿到很多测试点

    代码

    #include<iostream>
    #include<stdio.h>
    #include<cstring>
    using namespace std;
    #define maxn 1005000
    int n,m,k,x,y;
    int fa[maxn];
    int vis[maxn];
    int fi(int x)
    {
        return fa[x]==x?x:fa[x]=fi(fa[x]);
    }
    int flag = 0;
    int tot = 0;
    void uni(int x,int y)
    {
        int p = fi(x);
        int q = fi(y);
        if(p==q)
            flag=1;
        if(p!=q)
        {
            fa[p]=q;
            tot++;
        }
    }
    int get(int x,int y)
    {
        long long p = x*m-m+y;
        return p>1000000?1000001:p;
    }
    int main()
    {
        int t;scanf("%d",&t);
        while(t--)
        {
            tot = 0;
            memset(vis,0,sizeof(vis));
            scanf("%d%d%d",&n,&m,&k);
            if(1ll*n*m>1000000){puts("No");for(int i=1;i<=k;i++)scanf("%d%d",&x,&y);continue;}
            for(int i=1;i<=k;i++)
            {
                scanf("%d%d",&x,&y);
                vis[get(x,y)]=1;
            }
            for(int i=1;i<=n*m;i++)
                fa[i]=i;
            flag = 0;
            for(int i=1;i<=n*m;i++)
            {
                if(vis[i]==0)
                {
                    if(i%m==0&&!vis[i-m+1])
                        uni(i-m+1,i);
                    if(i%m!=1&&!vis[i-1])
                        uni(i-1,i);
                    if(i>m&&!vis[i-m])
                        uni(i-m,i);
                    if(flag)break;
                }
                if(flag)break;
            }
            if(flag||tot+1!=n*m-k)
                printf("No
    ");
            else
                puts("Yes");
        }
    }
  • 相关阅读:
    算法提高 身份证号码升级
    枚举排列
    排列数
    算法训练 K好数
    算法训练 前缀表达式
    算法训练 区间k大数查询
    最大最小公倍数
    Anagrams问题
    Uiautomator 2.0
    Uiautomator 2.0
  • 原文地址:https://www.cnblogs.com/qscqesze/p/4929581.html
Copyright © 2011-2022 走看看