King's Tour

题面大意

在 \(n\times m\) 的网格中构造一种从 \((1,1)\) 走到 \((a,b)\) 的方案,要求经过所有格子恰好一次,格子之间八联通。

思路分析

模拟赛题,赛时写了一个半小时过了(

思路不是很复杂,但是需要一些分类讨论。


  • 引理:对于任意大小的矩形,一定存在从左上走到右下的方案。

  • 证明:

若长宽中有一个是奇数,那么我们可以按照如下方案构造:

否则,我们可以按照如下方案构造:


那么同理,我们只需要将矩形翻转就可以得到从矩形一个角走到对角的方案。

walk(x1, y1, x2, y2) 表示输出从 \((x_1,y_1)\) 走到 \((x_2,y_2)\),填满以 \((x_1,y_1)\) 和 \((x_2,y_2)\) 作为对角线的矩形的方案。

而当我们考虑从 \((1,1)\) 走到 \((a,b)\) 时,我们进行分类讨论,下面是图示和代码实现:

(蓝色边表示用引理的方案填满整个矩形,绿色边表示实际走的边。)

  • \(a=n,b=m\):

walk(1, 1, a, b)
  • \(a=1,b=m\):

walk(1, 1, n, m - 1);
walk(n, m, a, b);
  • \(a=n,b=1\):

walk(1, 1, n - 1, m);
walk(n, m, a, b);
  • \(a=1,b\not =m\):

walk(1, 1, n, b - 1);
walk(n, b, 2, m);
walk(1, m, a, b);
  • \(b=1,a\not =n\):

walk(1, 1, a - 1, m);
walk(a, m, n, 2);
walk(n, 1, a, b);
  • \(a=n,b\not =1\):

walk(1, 1, n, b - 1);
walk(n - 1, b, 1, b);
walk(1, b + 1, n - 1, m);
walk(n, m, a, b);
  • \(b=m,a\not =1\):

walk(1, 1, a - 1, m);
walk(a, m - 1, n - 1, 1);
walk(n, 1, n, m);
walk(n - 1, m, a, b);
  • \(a\in[2,n-1],b\in[2,m-1]\):

walk(1, 1, a - 1, m);
walk(a, m, n, b + 1);
walk(n, b, a + 1, 1);
walk(a, 1, a, b);

那么这题就愉快的结束了,时间复杂度显然是 \(O(n^2)\)。

代码

(109 行,3.5k)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath> using namespace std;
const int N = 200200;
#define inf 0x3f3f3f3f int n, m, a, b; namespace SOL{
void walk(int x1, int y1, int x2, int y2){
int dir;
if (x1 <= x2 && y1 <= y2) dir = 1;
if (x1 > x2 && y1 <= y2) dir = 3;
if (x1 <= x2 && y1 > y2) dir = 2;
if (x1 > x2 && y1 > y2) dir = 4;
if (x1 > x2) swap(x1, x2);
if (y1 > y2) swap(y1, y2);
int n = x2 - x1 + 1, m = y2 - y1 + 1;
vector <pair<int, int>> v;
if ((n & 1) || (m & 1)) {
if (n & 1) {
int x = 1, y = 0, d = 1;
for (int i = 1; i <= n * m; i ++) {
y += d;
if (y == m + 1) y = m, x ++, d = -d;
if (y == 0) y = 1, x ++, d = -d;
v.push_back({x, y});
}
}
else {
int x = 0, y = 1, d = 1;
for (int i = 1; i <= n * m; i ++) {
x += d;
if (x == n + 1) x = n, y ++, d = -d;
if (x == 0) x = 1, y ++, d = -d;
v.push_back({x, y});
}
}
}
else {
int x = 1, y = 0, d = 1;
for (int i = 1; i <= (n - 2) * m; i ++) {
y += d;
if (y == m + 1) y = m, x ++, d = -d;
if (y == 0) y = 1, x ++, d = -d;
v.push_back({x, y});
}
for (int i = 1; i <= m; i ++) {
v.push_back({n - 1, i});
v.push_back({n, i});
}
}
if (dir == 2) for (auto &it : v) it.second = m - it.second + 1;
if (dir == 3) for (auto &it : v) it.first = n - it.first + 1;
if (dir == 4) for (auto &it : v) it.first = n - it.first + 1, it.second = m - it.second + 1;
for (auto it : v) cout << it.first + x1 - 1 << ' ' << it.second + y1 - 1 << '\n';
}
void work(){
if (a == n && b == m) {
walk(1, 1, n, m);
}
else if (a == n && b == 1) {
walk(1, 1, n - 1, m);
walk(n, m, a, b);
}
else if (a == 1 && b == m) {
walk(1, 1, n, m - 1);
walk(n, m, a, b);
}
else if (a == 1) {
walk(1, 1, n, b - 1);
walk(n, b, 2, m);
walk(1, m, a, b);
}
else if (b == m) {
walk(1, 1, a - 1, m);
walk(a, m - 1, n - 1, 1);
walk(n, 1, n, m);
walk(n - 1, m, a, b);
}
else if (a == n) {
walk(1, 1, n, b - 1);
walk(n - 1, b, 1, b);
walk(1, b + 1, n - 1, m);
walk(n, m, a, b);
}
else if (b == 1) {
walk(1, 1, a - 1, m);
walk(a, m, n, 2);
walk(n, 1, a, b);
}
else {
walk(1, 1, a - 1, m);
walk(a, m, n, b + 1);
walk(n, b, a + 1, 1);
walk(a, 1, a, b);
}
}
} int main(){
scanf("%d %d %d %d", &n, &m, &a, &b);
return SOL::work(), 0;
}

King's Tour 题解的更多相关文章

  1. POJ2135:Farm Tour——题解

    http://poj.org/problem?id=2135 题目大意: 从1到n再回来,每条边只能走一次,问最短路. —————————————————— 如果不告诉我是费用流打死不会想这个…… 我 ...

  2. LuoguP7041 [NWRRC2016]King's Heir 题解

    Content 给出现在的日期,请从 \(n\) 个人当中选出一个人,使得他是所有成年人(\(\geqslant 18\) 岁的人)中年龄最小的. 数据范围:设日期为 \(yy/mm/dd\),则有 ...

  3. M-SOLUTIONS Programming Contest 2021(AtCoder Beginner Contest 232) 题解

    目录 G - Modulo Shortest Path H - King's Tour 因为偷懒就只写G和H的题解了. G - Modulo Shortest Path 首先可以观察到对于一条从点\( ...

  4. ACM - 动态规划 - UVA 1347 Tour

    UVA 1347 Tour 题解 题目大意:有 \(n\) 个点,给出点的 \(x\).\(y\) 坐标.找出一条经过所有点一次的回路,从最左边的点出发,严格向右走,到达最右点再严格向左,回到最左点. ...

  5. [COGS 2583]南极科考旅行

    2583. 南极科考旅行 ★★   输入文件:BitonicTour.in   输出文件:BitonicTour.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 小美要 ...

  6. 【题解】Sigitseeing Tour

    题目大意 有一张$n$个结点,$m$条混合边的图($1 \leq n \leq 200$,$1 \leq m \leq 1000$),求这张图是否存在欧拉回路. 题解 因为有混合边,所以我们要先给无向 ...

  7. World Tour Finals 2019 D - Distinct Boxes 题解

    太神了,专门写一篇题解 qwq 简要题意:给你 \(R\) 个红球和 \(B\) 个蓝球,你要把它们放到 \(K\) 个箱子里,要求没有两个箱子完全相同(即两种球个数就相同),求 \(K\) 的最大值 ...

  8. Money King【题解】

    我又傻了……竟然忘了区别大根堆和小根堆的性质,以至于一个符号打错,debug了半天……(我真是太菜了……) 题目描述 Once in a forest, there lived N aggressiv ...

  9. POJ 1904 King's Quest(强连通图)题解

    题意:n个王子有自己喜欢的ki个公主,有n个公主,每个王子只能娶一个自己喜欢的公主且不能绿别的王子.现在给你一种王子娶公主的方案,并且保证这种方案是正确的.请你给出,每个王子能娶哪些公主,要求娶这些公 ...

  10. POJ2728:Desert King——题解

    http://poj.org/problem?id=2728 题目大意:求一棵生成树使得路费用和/路长之和最小(路的费用是两端点的高度差) 最小比率生成树. 我们还是01分数规划的思想将边权变为路费用 ...

随机推荐

  1. Task Execution and Scheduling In SpringBoot

    开天辟地 Task Execution and Scheduling In the absence of an Executor bean in the context, Spring Boot au ...

  2. List子集合__小记

    List集合的子实现类的特点: ArrayList: 底层数据结构是数组的形式,满足数组结构的特点:查询快,增删慢 从线程安全问题来看:线程不安全的,不同步,执行效率高 Vector: 底层数据结构是 ...

  3. PNG结构

    参考此博客 PNG的文件头总是固定的八个字节 89 50 4E 47 0D 0A 1A 0A 数据块长度13 00 00 00 0D 文件头数据块标识IDCH 49 48 44 52 13位数据块(I ...

  4. boinc使用笔记

    安装 yum install -y epel-release yum install -y boinc-client boinc-manager 启动 在图形界面开启终端 boinc boincmgr

  5. k8s+containerd安装

    准备环境 准备两台服务器节点,如果需要安装虚拟机,可以参考<wmware和centos安装过程> 机器名 IP 角色 CPU 内存 centos01 192.168.109.130 mas ...

  6. Linux 安装:中文manpages

    Linux 中文man手册安装 bash 脚本 wget https://src.fedoraproject.org/repo/pkgs/man-pages-zh-CN/manpages-zh-1.5 ...

  7. javascript中的垃圾回收机制的一些知识记录

    调用栈中的数据是如何回收的 原始类型的数据会分配到栈中 引用类型的数据会被分配到堆中 在执行代码的过程中,如果遇到了一个函数,js引擎会创建该函数的执行上下文,并将该函数的上下文压入调用栈中,与此同时 ...

  8. IDEA:使用Test注解,控制台无法输入

    解决方案 步骤一: 点击help ===> Edit Custom VM Options... 步骤二: 添加文件末尾添加如下内容 -Deditable.java.test.console=tr ...

  9. SpringCloud-Hystrix服务熔断与降级工作原理&源码

    先附上Hystrix源码图 在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用 ...

  10. 一些不错的VSCode设置和插件

    设置 同步设置 我们做的各项设置,不希望再到其他机器的时候还得再重新配置一次.VSCode中我们可以登陆微软账号或者GitHub账号,登陆后我们可以开启同步设置.开启设置同步,根据提示登陆即可. 允许 ...