嘘~ 正在从服务器偷取页面 . . .

UOJ142 【UER #5】万圣节的南瓜灯 题解


UOJ142 【UER #5】万圣节的南瓜灯 题解

题目链接:#142. 【UER #5】万圣节的南瓜灯

题意

cxy 是一个心灵手巧的女孩纸。今天是万圣节, cxy 正在家里制作南瓜灯。

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

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

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

现在 cxy 有 \(T\) 个南瓜灯,她想让你帮她分别判断每一个南瓜灯能不能被做成工艺品。

输入格式

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

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

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

数据保证 \(n,m \geq 3\)\(0 \leq k < nm\) 且不会重复描述一个被弄坏的格子。

输出格式

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

数据范围

\(n,m \le 10^9,~k\le 10^5\)

直接暴力建图坑定是不行滴。

但是我们可以从 \(k\) 的范围估测出有效点数

因为当点数很多的时候,很难产生一棵树,因此这一定有个上界

点数很简单,肯定是 \(|V|=nm-k\)

考虑边数,\(nm\) 条横向边 + \((n-1)m\) 条纵向边 = \((2n-1)m\) 条边

而每次删掉一条边至多删去 \(4\) 条边,故 \[ |E| \ge (2n-1)m - 4k \] 由于 \(|E|=|V|-1\) ,则 \[ nm-k-1 \ge (2n-1)m-4k \]\[ 3k \ge (n-1)m+1 \] 如果不满足这个条件直接输出No就好了

你看这个 \((n-1)\)是不是很难看,于是尝试要找到 \(n\)\(n-1\) 的关系

离谱的来了 \[ n\ge 3 \Rightarrow n \le \dfrac{3}{2} (n-1) \] 因此 \[ |V| < nm \le \dfrac{3}{2}(n-1)m < \dfrac{9}{2}k \le 4.5\times 10^5 \] 于是直接 \(\mathtt{dfs}\) 就好啦!

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N ((int)(5e5+15))
#define cxy static int x;
#define is for(int i=1; i<=k; i++)
#define very cin >> x >> x;
#define cute return 0
#define haha(r,c) ((r-1) * m + c)
const int dx[] = {0,0,1,-1};
const int dy[] = {1,-1,0,0};
int n,m,k,used[N],ck[N];
bool dfs(int x,int y,int la=0)
{
    int cur=haha(x,y),tx,ty,nx;
    used[cur] = 1;
    for(int d=0; d<4; d++)
    {
        tx=x+dx[d]; ty=(y+dy[d]+m-1) % m + 1; nx=haha(tx,ty);
        if(tx >= 1 && tx <= n && !ck[nx] && nx!=la)
            if(used[nx] || !dfs(tx,ty,cur)) return 0;
    }
    return 1;
}
bool work()
{
    cin >> n >> m >> k; int i,j=0;
    if(3 * k <= (n-1) * m) {cxy is very cute;}
    memset(used,0,sizeof(used));
    memset(ck,0,sizeof(ck));
    for(int i=1,u,v; i<=k; i++) cin >> u >> v,ck[haha(u,v)] = 1;
    for(i=1; i<=n; i++)
    {
        for(j=1; j<=m; j++)
            if(!ck[haha(i,j)] && !used[haha(i,j)])
                {if(!dfs(i,j)) return 0; else break;} // find a root
        if(j<=m) break;
    } 
    for(i=haha(i,j); i<=n*m; i++)
        if(!ck[i] && !used[i]) return 0; // can't reach
    return 1;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int Q;for(cin >> Q; Q--; ) cout << (work() ? "Yes\n" : "No\n");
    return 0;
}

参考文献

[1] https://yhx-12243.github.io/OI-transit/records/uoj142.html


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录