【AcWing】蓝桥杯集训每日一题Day16|哈希|FloodFill算法|字典序最小|映射|1402.星空之夜(C++)

news2024/11/29 3:19:42
1402.星空之夜
1402. 星空之夜 - AcWing题库
难度:中等
时/空限制:1s / 64MB
总通过数:3415
总尝试数:7434
来源:

usaco training 5.1
算法标签

Flood Fill哈希DFSBFS

题目内容

夜空深处,闪亮的星星以星群的形式出现在人们眼中,形态万千。
一个星群是指一组非空的在水平,垂直或对角线方向相邻的星星的集合。
一个星群不能是一个更大星群的一部分。
星群可能是相似的。
如果两个星群的形状、包含星星的数目相同,那么无论它们的朝向如何,都认为它们是相似的。
通常星群可能有 8 种朝向,如下图所示:
starry-1.gif
现在,我们用一个二维 01 矩阵来表示夜空,如果一个位置上的数字是 1,那么说明这个位置上有一个星星,否则这个位置上的数字应该是 0。
给定一个夜空二维矩阵,请你将其中的所有星群用小写字母进行标记,标记时相似星群用同一字母,不相似星群用不同字母。
标注星群就是指将星群中所有的 1 替换为小写字母。

输入格式

第一行包含一个整数 W,表示矩阵宽度。
第二行包含一个整数 H,表示矩阵高度。
接下来 H 行,每行包含一个长度为 W 的 01 序列,用来描述整个夜空矩阵。

输出格式

输出标记完所有星群后的二维矩阵。
用小写字母标记星群的方法很多,我们将整个输出读取为一个字符串,能够使得这个字符串字典序最小的标记方式,就是我们想要的标记方式。
输出这个标记方式标出的最终二维矩阵。

数据范围

0≤W,H≤100,
0≤ 星群数量 ≤500,
0≤ 不相似星群数量 ≤26,
1≤ 星群中星星的数量 ≤160

输入样例:
23
15
10001000000000010000000
01111100011111000101101
01000000010001000111111
00000000010101000101111
00000111010001000000000
00001001011111000000000
10000001000000000000000
00101000000111110010000
00001000000100010011111
00000001110101010100010
00000100110100010000000
00010001110111110000000
00100001110000000100000
00001000100001000100101
00000001110001000111000
输出样例:
a000a0000000000b0000000
0aaaaa000ccccc000d0dd0d
0a0000000c000c000dddddd
000000000c0b0c000d0dddd
00000eee0c000c000000000
0000e00e0ccccc000000000
b000000e000000000000000
00b0f000000ccccc00a0000
0000f000000c000c00aaaaa
0000000ddd0c0b0c0a000a0
00000b00dd0c000c0000000
000g000ddd0ccccc0000000
00g0000ddd0000000e00000
0000b000d0000f000e00e0b
0000000ddd000f000eee000
样例解释

样例对应的星空图如下:
starry-2.gif
答案对应的标记后星空图如下:
starry-3.gif

题目解析

给一个矩阵,表示夜空,用黑色的块表示星星,连通块是八连通,只要有公共的边和点,都算连通
每一个连通块都算一个星群,星群里面有八种朝向,通过旋转和对称得到的这八种朝向是等价的
矩阵的形式是01二维矩阵,0表示空,1表示有星星
找出其中所有相同的星群,要把所有的星群归类,相同的归为一类,不同的归为另外一类
同一类星群用同一个小写英文字母标记,不同的星群用不同的英文小写字母标记

矩阵最大的长宽是100x100
星群数量最大是500
不相同的星群数量不会超过26个,一定可以用26个英文字母全部标记出来
标记的时候,是把星群用对应的字母替换掉,同一种星群用同一个字母替换
输出的时候,标记的方案有很多种,为了方便评测,规定输出一个字典序最小的方案,就是把每一行拼接起来,拼成一个字符串

1. 怎么去找一个星群

找一个星群就是找连通块,可以用Flood Fill算法,BFS、DFS或并查集,把所有连通块找出来

2. 如何区分星群

因为数据范围比较小,最多只会包含500个星群,每个星群中最多只会包含160个星星
可以使用暴力的方式去找,可以把星群所有出现的坐标存到一个数组里,每一次拿到一个新的星群之后,判断一下它在存过的星群里面有没有出现过,一个一个去比一遍,出现过的话,就是同一类,没有出现过的话,就是一种全新的类,时间复杂度是 O ( 500 ∗ 26 ∗ 160 ) O(500*26*160) O(50026160),真实情况会比这个小很多
用暴力的方法比较,把八种朝向都枚举一遍,x8,最多1664万的计算量,可以过

[!NOTE] 如何优化
字符串哈希
因为只需要辨别是相同还是不同
把很多星群的所有信息,想办法把每一个星群,把它映射到一个数,再去判断这个数在前面有没有出现过

  1. 如何把星群转化成数
    和字符串哈希一样,字符串哈希是把字符串转化成一个数,不能保证不冲突,有可能把不同形状的星群映射到同一个数,可以选择一种出现这种情况概率极低的一种哈希方式
    这类算法不能保证一定是正确的,但是可以保证99%是正确的,不是精确算法,但是可以认为基本上是精确的
    如字符串哈希,哈希值不一样,原字符串一定一样,哈希值一样,原字符串不一定一样,但是大概率是一样的
    包括快排和哈希表
  • 快排在平均意义上是nlogn,极限情况下时间复杂度是n^2,但是可以认为极限情况很难出现,
  • 哈希表均摊是O(1)的,极端情况下也可以产生O(n)
  1. 怎么哈希
    这个哈希方法应该尽量让它对旋转和对称是不敏感的,就是不管是旋转还是对称都不影响哈希值,
    计算星群当中两个点两两之间,比如总共有k个点,就有 C k 2 C_{k}^2 Ck2种关系,每两个点之间的欧几里得距离,直线距离的总和
    这种哈希方式是比较好的,如果是曼哈顿距离的话,冲突的概率更大

如果这种哈希方法答案错误的话,可以提供两个哈希值,哈希值1,就是计算一下直线距离的总和,再用另外一个哈希函数,两个哈希函数都判错的情况就比较低了

通过这样的哈希方式可以将星群映射成一个浮点数,还会去除掉旋转和对称的影响

整个图做一遍,包含1万个点,计算量是1万;星群最多是500个,每个星群枚举一遍,比较26次,是两万多的计算量

3. 如何保证字典序最小

对于大部分问题,要求字典序最小都不会增加题目的难度,主要是为了方便评测
从第一行开始枚举,当找到第一个1的时候,就把第一个1所在的连通块找出来,给这个连通块赋一个什么字母
出现过的话,赋出现过的字母
没有出现过的话,赋当前没有出现过的最小的字母
当前没有出现过的字母如果是a的话,是按照字符串的顺序一个一个枚举的,当前字母选a的话,一定比选大于a的字母的字典序更小
所以从前往后找的时候,如果发现了一个新的星群,就从小到大赋字母,这样可以保证字典序是最小的

比较浮点数是不是相等的时候,需要考虑精度(参考上一篇)

代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 110, M = 170;
const double eps = 1e-8;

int n, m;
char g[N][N];
PII q[M];    //用pair数组存所有的星群的坐标
int top = 0; //当前星群星星的数量
double hash_val[30]; //把前面所有出现过的星群的哈希值都存下来
int cnt = 0;  //当前不同星群的数量

void dfs(int a, int b)
{
	//先把当前的星星存下来
	q[top ++] = {a, b};
	//已经搜过的话,标记为0
	g[a][b] = '0';

	//枚举一下周围八个方向
	for (int x = a - 1; x <= a + 1; x ++)
		for (int y = b - 1; y <= b + 1; y ++)
			//如果发现当前的下标没有越界,并且当前的位置是1
			if (x >= 0 && x < n && y >= 0 && y < m && g[x][y] == '1')
				dfs(x, y);
}

double get_dist(PII& a, PII& b)
{
	//先求一下坐标之差
	double dx = a.x - b.x, dy = a.y - b.y;
	return sqrt(dx * dx + dy * dy);
}

double get_hash()
{
	double sum = 0;
	//等于所有点对之间的距离之和
	for (int i = 0; i < top; i ++)
		for (int j = 0; j < i; j ++)
			sum += get_dist(q[i], q[j]);
	return sum;
}

char get_id()
{
	//先求当前星群的哈希值
	double val = get_hash();
	//判断之前有没有出现过
	for (int i = 0; i < cnt; i ++)
		if (abs(hash_val[i] - val) < eps)
			return 'a' + i;
	//如果没有出现过,存下来
	hash_val[cnt ++] = val;
	return 'a' + cnt - 1;
}

int main()
{
	//读入m和n
	scanf("%d%d", &m, &n);
	//读入整个矩阵
	for (int i = 0; i < n; i ++) scanf("%s", g[i]);

	//从前往后依次枚举每一个位置
	for (int i = 0; i < n; i ++)
		for (int j = 0; j < m; j ++)
			//如果发现当前的位置是1的话,表示发现了一个新的星群
			if (g[i][j] == '1')
			{
				top = 0;  //先把top清空
				dfs(i, j); //floodfill 把所有和i,j连通的星星找出来
				//求一下当前星群的id
				char id = get_id();

				//把所有的格子赋成id
				for (int k = 0; k < top; k ++)
					g[q[k].x][q[k].y] = id;
			}
	//输出整个矩阵
	for (int i = 0; i < n; i ++) puts(g[i]);
	//puts等价于printf %s\n
}

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

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

相关文章

雅特力AT32引脚复用记录

用作USB的话&#xff0c;PA9不能再用作其他功能了 被复用了。这个关联信号是OTG_FS_VBUS。stm32是能这么复用的。

大型央国企“信创化”与数字化转型建设思路

一、央国企信创化与数字化转型时代背景 1、信创概念普及&#xff1a; 信创&#xff0c;即“信息技术应用创新”。是我国自主信息产业聚焦的核心&#xff0c;旨在通过对IT硬件、软件等各个环节的重构&#xff0c;基于我国自有IT底层架构和标准&#xff0c;形成自有开放生态&am…

阿里云OSS使用流程

准备工作 无论怎么样&#xff0c;你需要准备一个阿里云账号&#xff0c;点击&#xff1a;注册阿里云 输入相关信息&#xff0c;然后注册成功以后&#xff0c;点击 然后注册成功了&#xff0c;实名一下阿里云账号。打开实名入口&#xff0c;选择个人实名或者企业实名。 如果你…

Xinstall:专业的App下载量统计工具,让推广效果可衡量

在移动互联网时代&#xff0c;App的下载量是衡量一个应用受欢迎程度的重要指标。然而&#xff0c;很多开发者和广告主在推广App时&#xff0c;都面临着一个共同的问题&#xff1a;如何准确统计App的下载量&#xff1f;这不仅关系到推广效果的评估&#xff0c;还直接影响到广告R…

【Linux 学习】进程优先级和命令行参数!

1. 什么是优先级? 指定进程获取某种资源&#xff08;CPU&#xff09;的先后顺序&#xff1b; Linux 中优先级数字越小&#xff0c;优先级越高&#xff1b; 1.1 优先级和权限的区别&#xff1f; 权限 &#xff1a; 能不能做 优先级&#xff1a; 已经能了&#xff0c;但是获…

Linux初学(十七)防火墙

一、防火墙简介 1.1 防火墙的类别 安全产品 杀毒&#xff1a; 针对病毒&#xff0c;特征篡改系统中的文件杀毒软件针对处理病毒程序防火墙&#xff1a; 针对木马&#xff0c;特征系统窃取防火墙针对处理木马 防火墙分为两种 硬件防火墙软件防火墙 硬件防火墙 各个网络安全…

模型量化——NVIDIA——方案选择(PTQ、 partialPTQ、 QAT)

PTQ、 partialPTQ、 QAT 选择流程 PTQ、 partialPTQ、 QAT 咨询NVIDIA 官方后&#xff0c;他们的校正过程一致&#xff0c;支持的量化算子本质是一样的&#xff0c;那么如果你的算子不是如下几类&#xff0c;那么需要自己编写算子。参考TensorRT/tools/pytorch-quantization/py…

淘宝销量API商品详情页原数据APP接口测试㊣

淘宝/天猫获得淘宝app商品详情原数据 API 返回值说明 item_get_app-获得淘宝app商品详情原数据 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地…

码蹄集部分题目(第五弹;OJ赛2024年第10期)

&#x1f40b;&#x1f40b;&#x1f40b;竹鼠通讯&#xff08;钻石&#xff1b;分治思想&#xff1b;模板题&#xff1a;就算几何平面点对问题&#xff09; 时间限制&#xff1a;3秒 占用内存&#xff1a;128M &#x1f41f;题目描述 在真空中&#xff0c;一块无限平坦光滑…

基于SSM+Jsp+Mysql的高校毕业设计管理系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

【三十六】【算法分析与设计】综合练习(3),39. 组合总和,784. 字母大小写全排列,526. 优美的排列

目录 39. 组合总和 对每一个位置进行枚举 枚举每一个数出现的次数 784. 字母大小写全排列 526. 优美的排列 结尾 39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不…

【信贷后台管理之(五)】

文章目录 目录结构一、面包屑组件封装二、退出登录接口联调三、申请列表的菜单路由3.1 路由创建&#xff0c;表格编写3.2 列表接口调用3.3 出生日期转变3.4 申请状态3.5 申请列表的操作3.5.1 编辑删除提交操作3.5.2 禁用状态3.5.3 操作接口3.5.4 搜索查询3.5.5 申请列表分页功能…

Leetcode面试经典150_Q14最长公共前缀

题目&#xff1a; 编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀&#xff0c;返回空字符串 ""。 思路A&#xff1a;横向/纵向扫描 Python&#xff1a; class Solution:def longestCommonPrefix(self, strs: List[str]) -> str:s "…

NPDP含金量高吗?什么人适合学习NPDP?

省流版&#xff1a;NPDP含金量挺高的&#xff0c;做产品的建议去学习下~ 一、什么是NPDP&#xff1f; NPDP 是产品经理国际资格认证&#xff0c;美国产品开发与管理协会&#xff08;PDMA&#xff09;发起的&#xff0c;是目前国际公认的唯一的新产品开发专业认证&#xff0c;…

LeetCode-279. 完全平方数【广度优先搜索 数学 动态规划】

LeetCode-279. 完全平方数【广度优先搜索 数学 动态规划】 题目描述&#xff1a;解题思路一&#xff1a;Python 动态规划五部曲&#xff08;完全平方数就是物品&#xff08;可以无限件使用&#xff09;&#xff0c;凑个正整数n就是背包&#xff0c;问凑满这个背包最少有多少物品…

小明的衣服-蓝桥1228-优先队列

解法 用优先队列&#xff0c;思路参考哈夫曼树&#xff08;贪心&#xff09; 思路&#xff1a;很复杂&#xff0c;说结果 n件同色衣服要染成都不同色&#xff0c;求邮费最少&#xff1b; 倒过来想&#xff1a;n件不同颜色衣服&#xff0c;要染成同一种颜色&#xff0c;求邮费…

tensorflow.js 使用 opencv.js 将人脸特征点网格绘制与姿态估计线绘制结合起来,以获得更高的帧数

系列文章目录 如何在前端项目中使用opencv.js | opencv.js入门如何使用tensorflow.js实现面部特征点检测tensorflow.js 如何从 public 路径加载人脸特征点检测模型tensorflow.js 如何使用opencv.js通过面部特征点估算脸部姿态并绘制示意图 文章目录 系列文章目录前言一、实现步…

Python高级

不定长参数 位置不定长参数&#xff0c;获取参数args会整合为一个元组 def info(*args):print(arg is, args)print(type(arg) is, type(args))info(1, 2, 3, 4, a, b)# 输出 # arg is (1, 2, 3, 4, a, b) # type(arg) is <class tuple> 关键字不定长参数&#xff0c;&…

JavaSE:图书管理系统

目录 一、前言 二、内容需求 三、类的设计 &#xff08;一&#xff09;图书类 1.Book 类 2.BookList 类 &#xff08;二&#xff09;操作类 1.添加图书AddOperation类 2.借阅图书BorrowOperation类 3.删除图书DelOperation类 4.显示图书ShowOperation类 5.退出系统Ex…

Python代码识别minist手写数字【附pdf】

一、概述 对于人类而言,要识别图片中的数字是一件很容易的事情,但是,如何让机器学会理解图片上的数字,这似乎并不容易。那么,能否找出一个函数(模型),通过输入相关的信息,最终得到期望的结果呢? 二、python代码实现中涉及的输入输出内容: 输入:mnist数据集每一个…