UVA-1602 网格动物 题解答案代码 算法竞赛入门经典第二版

GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版

使用dfs遍历所有情况,再去重即可。

遍历部分

遍历的时候需要注意:

1. 这其实并不能算是dfs,因为普通的dfs是一直走到尽头,然后再逐渐退出,走下一条路。到最后的路径是一条线。但是这个题目生成的图形却可以分叉。因此,递归一次dfs时,要循环遍历当前所有的节点,让所有的节点都可以分叉进行。

2. 如果直接遍历所有情况,那么肯定是超时的。我是这样做的:

我一开始尝试了从w*h区域的每个点开始遍历,遇到墙就返回。这样其实存在大量的重复,会重复生成一样的图形。我后面改造成了直接从(1, 1)点开始遍历。并不真实的设立一个墙。在生成的过程中,如果碰到这个图像的宽和高大于区域的大小,那么认为这个区域放不下这个图形,就退出。这中间出现坐标负值也是正常的。

3. 用上面的方法之后,还是有较多的超时。因此我们继续优化。这时候我们设定一个中间图形是否遍历过的set。假设该图形或者该图形的旋转,平移和镜像在set中存在了,就说明已经遍历过了,就不在往下进行。这样能够很大的缩小情况的种类。比如:[(1,1), (1,2)] 和 [(1,1), (2,1)] 等等都属于重复图形,也就是说,dfs的第二层依旧只有一个结点。这样节约的时间是很多的。

4. 用了上面的方法后,还是超时。但是即使输出全部的情况下,在本地电脑中也是比较快的,大概一两分钟左右。由于情况不多(不超过1000中情况),因此直接打表更适合。即我们在本地算出结果,把结果直接写在代码里。我直接在代码中写了n=10情况下的所有输出,其他情况下还是实时计算的。这样最后AC了。

如何对图形进行的旋转,平移和镜像

除了遍历之外,还有一个注意的点就是,如何对图形进行的旋转,平移和镜像。且能在set中标识这个图形。

1. 标识图形

由于每个点的的最大坐标为(1-10,1-10),最多10个点,因此标识所有情况需要 10^20。64位存不下。换一种表示法,用起点加转向,就是100*4^9, 64位存下绰绰有余。但是我们并不是一条路径,可以有分叉,因此这种方式做不到。

还有一个问题就是,存在set中的结构要保证唯一性,即同样一个图形,如果点的位置不一致,也可以找到。这时候我们就想到用set存储单个图形。然后单个图形的set元素是一个int,里面的值是100 * x + y。由于set是排好序的,因此我们的点在里面就是天然排序的,先按照x值排序,在按照y值排序。这样可以保证点不会因为位置交换了而判断为两个图形。

当然,100 * x + y的方法在遇到负值是有很大的问题,后面我又进行了改进。网络上还有人用其他方法可以存储单个点的,也可以参考。假设我们的点是(1, -1),那么值是-99。还原回点的时候,就变成了(0, -99)。

我的解决方案是,让值保持整数: 100 * x + y  ——>  100 *(x+20) + y + 20。由于坐标最大为10,因此计算的结果肯定是正的,还原回来也肯定是正的。

2. 平移

平移非常简单,我们让以x坐标和y坐标最小值为基准,设为1。其他的点平移这个差值即可。

这个平移的作用实际上是标准化,即将在不同位置的图形,都平移到一个位置,如果他是一个图形,那么平移之后位置是一致的。

3. 旋转图形

我们只需要实现转90度的方法即可。转两次就是180,三次就是270。

向右转90度,对于图形来说,坐标变化就是:(x, y) -> (y, -x)。画个图试一下就能看出规律了。因此,每次旋转时我们执行这个变化即可。

旋转之后还要平移一次。

4. 镜像图形

我们随便横向镜像和纵向镜像都可以,因此横向镜像后转90度就变为纵向镜像了。镜像更简单,x或者y的符号变一下即可。这时候我们注意到一点:

如果我们的点坐标是0,镜像完还是0,那肯定是不正确的。因此坐标从1开始,即1 - 10。1的前一个点是-1,我们没有0这个点。这时候平移和遍历就出问题了:

1和-1中间的差值是2不是1,我们如果正常遍历, 会走到0这个点。我们平移的时候如果图形中间穿过0这条线,那么减的值是不正确的。因此,我们要相应做处理,如果坐标值碰到0,根据情况设为1或者-1。平移的时候区分中间有0和没有0的情况。

AC代码

#include<stdio.h>
#include<string>
#include<string.h>
#include<set>using namespace std;int n, w, h;
int steps[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
// 数量
int num;
set<int> seArr, seTemp;
set<set<int>> se;
int arrTemp[10][2];
// 该状态是否访问过 
set<set<int>> seFlag;int tenTable[1000] = {0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,16,68,108,117,118,0,0,0,21,277,842,1226,1329,1338,1339,0,0,21,287,1847,3234,3773,3876,3885,3886,0,1,277,1847,2376,4003,4542,4645,4654,4655,0,16,842,3234,4003,4003,4542,4645,4654,4655,0,68,1226,3773,4542,4542,4542,4645,4654,4655,0,108,1329,3876,4645,4645,4645,4645,4654,4655,0,117,1338,3885,4654,4654,4654,4654,4654,4655,1,118,1339,3886,4655,4655,4655,4655,4655,4655};void getXY(int res, int &x, int &y) {x = res / 100 - 20;y = res % 100 - 20;
}void output(set<int> &setTemp) {int x, y;for(auto ip = setTemp.begin(); ip != setTemp.end(); ++ip) {getXY(*ip, x, y);printf("[%d,%d] ", x, y);}putchar('\n');
}int setXY(int x, int y) {return (x + 20) * 100 + y + 20;
}// 规范化 最小的x为 1 最小的y为 1
void standard(int (* arr)[2], int ntemp) {int i;int minX = arr[0][0], minY = arr[0][1];for(i = 1; i < ntemp; ++i) {if(arr[i][0] < minX) minX = arr[i][0];if(arr[i][1] < minY) minY = arr[i][1];}for(i = 0; i < ntemp; ++i) {if(arr[i][0] * minX > 0)arr[i][0] = arr[i][0] - minX + 1;elsearr[i][0] = arr[i][0] - minX;if(arr[i][1] * minY > 0)arr[i][1] = arr[i][1] - minY + 1;elsearr[i][1] = arr[i][1] - minY;}
}// 点的数组转为set 
void arr2Set(set<int> &setTemp, int (* arr)[2], int ntemp) {setTemp.clear();for(int i = 0; i < ntemp; ++i) {setTemp.insert(setXY(arr[i][0], arr[i][1]));}
}// set转为点的数组
void set2Arr(set<int> &setTemp, int (* arr)[2]) {int i = 0;for(auto ip = setTemp.begin(); ip != setTemp.end(); ++ip, ++i) {getXY(*ip, arr[i][0], arr[i][1]);}
}// 向右旋转90度
void turnRight(int (* arr)[2], int ntemp) {int j;for(int i = 0; i < ntemp; ++i) {j = arr[i][1];arr[i][1] = -arr[i][0];arr[i][0] = j;}
}// 镜像反转
void reserveArr(int (* arr)[2], int ntemp) {for(int i = 0; i < ntemp; ++i) {arr[i][0] = -arr[i][0]; }
}void judge(set<int> &setTemp) {if(se.count(setTemp)) return;++num;se.insert(seTemp);
}bool isBumpWall(set<int> &setTemp) {auto ip = setTemp.begin();int x, y;getXY(*ip, x, y);int minX = x, minY = y, maxX = x, maxY = y;for(ip = setTemp.begin(); ip != setTemp.end(); ++ip) {getXY(*ip, x, y);if(x < minX) minX = x;if(y < minY) minY = y;if(x > maxX) maxX = x;if(y > maxY) maxY = y;}x = maxX - minX - (maxX * minX < 0 ? 1 : 0);y = maxY - minY - (maxY * minY < 0 ? 1 : 0);if(((x >= w || y >= h) && (x >= h || y >= w)) || x + y >= n) return true;return false; 
} // 该模式的几种变形是否访问过 
bool findModel(int (* arr)[2], set<int> &setTemp, int ntemp) {if(seFlag.count(setTemp)) return true;int i;for(i = 0; i < 3; ++i) {// 转90度turnRight(arrTemp, ntemp);standard(arrTemp, ntemp);arr2Set(setTemp, arrTemp, ntemp);if(seFlag.count(setTemp)) return true;}// 镜像反转reserveArr(arrTemp, ntemp);for(i = 0; i < 4; ++i) {// 转90度if(i != 0) turnRight(arrTemp, ntemp);standard(arrTemp, ntemp);arr2Set(setTemp, arrTemp, ntemp);if(seFlag.count(setTemp)) return true;}return false; 
}void dfs(int count) {++count;int i, x, y, xi, yi, resi;for(auto ip = seArr.begin(); ip != seArr.end(); ++ip) {getXY(*ip, x, y);for(i = 0; i < 4; ++i) {xi = steps[i][0] + x;yi = steps[i][1] + y;if(xi == 0) {if(steps[i][0] > 0) xi = 1;if(steps[i][0] < 0) xi = -1;}if(yi == 0) {if(steps[i][1] > 0) yi = 1;if(steps[i][1] < 0) yi = -1;}resi = setXY(xi, yi);if(seArr.count(resi)) continue;seArr.insert(resi);set2Arr(seArr, arrTemp);standard(arrTemp, count);arr2Set(seTemp, arrTemp, count);if(!isBumpWall(seArr) && !findModel(arrTemp, seTemp, count)) {// 设置访问标记 seFlag.insert(seTemp);if(count == n) judge(seTemp);else dfs(count);}seArr.erase(resi);}}
}int compute() {num = 0;se.clear();seFlag.clear();seArr.clear();seArr.insert(setXY(1, 1));dfs(1);return num;
}int main() {while(scanf("%d %d %d", &n, &w, &h) == 3) {if(w * h < n) {printf("0\n");continue;}if(w * h == n || n == 1) {printf("1\n");continue;}if(n == 10) {printf("%d\n", tenTable[(w-1)*10 + h-1]);continue;}printf("%d\n", compute());}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/149372.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

润滑油泵控制(博途SCL源代码)

有关博途PLC定时器的各种使用方法请参考下面文章链接: 博途PLC IEC定时器编程应用(SCL语言)_博图 定时器-CSDN博客博途PLC定时器支持数据类型TIME 类型 ,写法支持T#2M10S 、T#10S等,时基是MS所以如果设置1M用 DINT数据类型就是60000,大部分HMI上数据类型很多不支持IEC的…

buuctf-[GXYCTF2019]禁止套娃 git泄露,无参数rce

用dirsearch扫一下&#xff0c;看到flag.php 访问一下没啥东西&#xff0c;使用githack python2 GitHack.py http://8996e81f-a75c-4180-b0ad-226d97ba61b2.node4.buuoj.cn/.git/查看index.php <?php include "flag.php"; echo "flag在哪里呢&#xff1f;…

【iptables 实战】9 docker网络原理分析

在开始本章阅读之前&#xff0c;需要提前了解以下的知识 阅读本节需要一些docker的基础知识&#xff0c;最好是在linux上安装好docker环境。提前掌握iptables的基础知识&#xff0c;前文参考【iptables 实战】 一、docker网络模型 docker网络模型如下图所示 说明&#xff1…

【算法|动态规划No.9】leetcodeLCR 091. 粉刷房子

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

Bee2.1.8支持Spring Boot 3.0.11,active命令行选择多环境,多表查改增删(bee-spring-boot发布,更新maven)

天下大势&#xff0c;分久必合&#xff01; Hibernate/MyBatis plus Sharding JDBC Jpa Spring data GraphQL App ORM (Android, 鸿蒙) Bee Spring Cloud 微服务使用数据库更方便&#xff1a;Bee Spring Boot; 轻松支持多数据源&#xff0c;Sharding, Mongodb. 要整合一堆的…

牛客网国庆赛day3

B&#xff1a; 给定一个由小写字母组成的字符串S。你要逐个执行Q个操作。每个操作可以是以下两种类型之一&#xff1a; 修改&#xff1a;给定一个整数x。根据x的值修改字符串S。如果x是正数&#xff0c;则将S中最左边的x个字母移到S的右侧&#xff1b;如果x是负数&#xff0c;…

最短路径专题6 最短路径-多路径

题目&#xff1a; 样例&#xff1a; 输入 4 5 0 2 0 1 2 0 2 5 0 3 1 1 2 1 3 2 2 输出 2 0->1->2 0->3->2 思路&#xff1a; 根据题意&#xff0c;最短路模板还是少不了的&#xff0c; 我们要添加的是&#xff0c; 记录各个结点有多少个上一个结点走动得来的…

JS-Dom转为图片,并放入pdf中进行下载

1、将dom转换为图片 这里我们使用html2canvas工具插件先将dom转为canvas元素然后canvas拥有一个方法可以将绘制出来的图形转为url然后下载即可注意&#xff1a;如果元素使用了渐变背景并透明的话&#xff0c;生成的图片可能会有点问题。我下面这个案例使用了渐变背景实现元素对…

【进程管理】初识进程

一.何为进程 教材一般会给出这样的答案: 运行起来的程序 或者 内存中的程序 这样说太抽象了&#xff0c;那我问程序和进程有什么区别呢&#xff1f;诶&#xff1f;这我知道&#xff0c;书上说&#xff0c;动态的叫进程&#xff0c;静态的叫程序。那么静态和动态又是什么意思…

typescript: Builder Pattern

/*** file: CarBuilderts.ts* TypeScript 实体类 Model* Builder Pattern* 生成器是一种创建型设计模式&#xff0c; 使你能够分步骤创建复杂对象。* https://stackoverflow.com/questions/12827266/get-and-set-in-typescript* https://github.com/Microsoft/TypeScript/wiki/…

想要精通算法和SQL的成长之路 - 验证二叉树

想要精通算法和SQL的成长之路 - 验证二叉树 前言一. 验证二叉树1.1 并查集1.2 入度以及边数检查 前言 想要精通算法和SQL的成长之路 - 系列导航 并查集的运用 一. 验证二叉树 原题链接 思路如下&#xff1a; 对于一颗二叉树&#xff0c;我们需要做哪些校验&#xff1f; 首先…

(二)正点原子STM32MP135移植——TF-A移植

目录 一、TF-A概述 二、编译官方代码 2.1 解压源码 2.2 打补丁 2.3 编译准备 &#xff08;1&#xff09;修改Makfile.sdk &#xff08;2&#xff09;设置环境变量 &#xff08;3&#xff09;编译 三、移植 3.1 复制官方文件 3.2 修改电源 3.3 修改TF卡和emmc 3.4 添…

学习记忆——方法篇——联想法+记忆宫殿+数字编码

左右脑在记忆当中的不同特点&#xff1a; 左脑是我们的理性脑。主要功能是处理逻辑内容、以及数字、文字等信息&#xff0c;擅长对知识的分析、理解、归纳、整合。缺点是处理信息速度慢、效率低&#xff0c;死记硬背就是用左脑记忆。 右脑是我们的感性脑。主要功能是处理节奏、…

2.2.2搭建交叉编译器

1 交叉编译器 交叉编译的存在,有2个原因,1个是不同的平台,架构不同,使用的指令集不同,ARM和MIPS的CPU无法运行X86指令休编码的程序,1个是一般arm平台上的存储/性能有限,无法提供一个可靠的编译环境。所以就出现了在x86上编译,在arm上运行的镜像,即交叉编译。在交叉编…

Linux多线程网络通信

思路&#xff1a;主线程&#xff08;只有一个&#xff09;建立连接&#xff0c;就创建子线程。子线程开始通信。 共享资源&#xff1a;全局数据区&#xff0c;堆区&#xff0c;内核区描述符。 线程同步不同步需要取决于线程对共享资源区的数据的操作&#xff0c;如果是只读就不…

网络是什么?(网络零基础入门篇)

1.如何理解局域网和广域网&#xff1f; 2.路由器和交换机是怎么样工作的&#xff1f; 3.三层交换机能不能代替路由器&#xff1f; -- 局域网 广域网 -- 企业网架构&#xff0c;运营商架构&#xff0c;数据中心架构 -- 局域网 通过 交换机连接的 转发 相同的ip地址…

stable diffusion学习笔记【2023-10-2】

L1&#xff1a;界面 CFG Scale&#xff1a;提示词相关性 denoising&#xff1a;重绘幅度 L2&#xff1a;文生图 女性常用的负面词 nsfw,NSFW,(NSFW:2),legs apart, paintings, sketches, (worst quality:2), (low quality:2), (normal quality:2), lowres, normal quality, (…

ubuntu下源码编译方式安装opencv

基础条件 ubuntu 20.04 opencv 3.4.3 opencv 源码编译的安装步骤 第一步&#xff0c; 首先clone源码 git clone https://github.com/opencv/opencv.git第二步&#xff0c;依赖包&#xff0c;执行下面的命令 sudo apt-get install build-essential sudo apt-get install cmak…

使用华为eNSP组网试验⑸-访问控制

今天练习使用华为sNSP模拟网络设备上的访问控制&#xff0c;这样的操作我经常在华为的S7706、S5720、S5735或者H3C的S5500、S5130、S7706上进行&#xff0c;在网络设备上根据情况应用访问控制的策略是一个网管必须熟练的操作&#xff0c;只是在真机上操作一般比较谨慎&#xff…

机器学习必修课 - 如何处理缺失数据

运行环境&#xff1a;Google Colab 处理缺失数据可简单分为两种方法&#xff1a;1. 删除具有缺失值的列 2. 填充 !git clone https://github.com/JeffereyWu/Housing-prices-data.git下载数据集 import pandas as pd from sklearn.model_selection import train_test_split导…