【哈希专题】【蓝桥杯备考训练】:星空之夜、模拟散列表、字符串哈希、四平方和、扫雷【已更新完成】

news2024/9/21 20:51:13

目录

1、星空之夜(usaco training 5.1)

2、模拟散列表(模板)

3、字符串哈希(模板)

4、四平方和(第七届蓝桥杯省赛C++ A组/B组 & JAVA B组/C组)

5、扫雷(Google Kickstart2014 Round C Problem A)


1、星空之夜(usaco training 5.1)

夜空深处,闪亮的星星以星群的形式出现在人们眼中,形态万千。

一个星群是指一组非空的在水平,垂直或对角线方向相邻的星星的集合。

一个星群不能是一个更大星群的一部分。

星群可能是相似的。

如果两个星群的形状、包含星星的数目相同,那么无论它们的朝向如何,都认为它们是相似的。

通常星群可能有 8 种朝向,如下图所示:

starry-1.gif

现在,我们用一个二维 01 矩阵来表示夜空,如果一个位置上的数字是 1,那么说明这个位置上有一个星星,否则这个位置上的数字应该是 0。

给定一个夜空二维矩阵,请你将其中的所有星群用小写字母进行标记,标记时相似星群用同一字母,不相似星群用不同字母。

标注星群就是指将星群中所有的 1 替换为小写字母。

输入格式

第一行包含一个整数 W,表示矩阵宽度。

第二行包含一个整数 H,表示矩阵高度。

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

输出格式

输出标记完所有星群后的二维矩阵。

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

输出这个标记方式标出的最终二维矩阵。

数据范围

0≤W,H≤1000
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

思路:

用欧几里得距离来辨别形状是否相同,用一个变量 id 来记录用到了第几个字母,top来记录连通块中点的数量,进行字母填充

代码:
//欧几里得距离 
//不能保证完全不相同,但能保证大概率不相同 
#include<bits/stdc++.h>

using namespace std;

const int N=101;
const double eps=1e-6;


int n,m;

typedef pair<int,int> PII;

char g[N][N];
PII q[N*N];
int top;//表示当前连通块有多少个点 
 
 


double get_dis(PII a,PII b)
{
	double dx=a.first - b.first;
	double dy=a.second - b.second;
	return sqrt(dx*dx+dy*dy);
}

double get_hash()
{
	double sum=0;
	
	for(int i=0;i<top;i++)
		for(int j=i+1;j<top;j++)
		{
			sum+=get_dis(q[i],q[j]) ;
		}
	return sum;
}

char get_id(double key)
{
	static double hash[30];//static 等价于全局变量 (每次调用函数,数组不会重新分配) 
	static char id=0;
	for(int i=0;i<id;i++)
	{
		if(fabs(hash[i]-key)<eps)
		{
			return i+'a';
		}
	} 
	hash[id++]=key;
	return id-1+'a';
}

void dfs(int a,int b)
{
	q[top++]={a,b};
	g[a][b]='0';
	for(int x=a-1;x<=a+1;x++)
		for(int y=b-1;y<=b+1;y++)
		{
			if(x==a && y==b)continue;
			if(x>=0 * y>=0 && x<n && y<m && g[x][y]=='1')
			{
				dfs(x,y);
			}
		}
	
}//flood fill

int main()
{
	cin>>m>>n;
	 
	for(int i=0;i<n;i++)
	{
		cin>>g[i]; 
	}
	 
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
		{
			if(g[i][j]=='1')
			{
				top=0;
				dfs(i,j);
				char c=get_id(get_hash());
				//cout<<c;
				for(int k=0;k<top;k++)
				{
				    //cout<<c<<endl;
					g[q[k].first][q[k].second]=c;
				}
			}
		}
	
	for(int i=0;i<n;i++)cout<<g[i]<<endl;
	
	 
	return 0;
} 

2、模拟散列表(模板)

维护一个集合,支持如下几种操作:

  1. I x,插入一个整数 x;
  2. Q x,询问整数 x 是否在集合中出现过;

现在要进行 N 次操作,对于每个询问操作输出对应的结果。

输入格式

第一行包含整数 N,表示操作数量。

接下来 N 行,每行包含一个操作指令,操作指令为 I xQ x 中的一种。

输出格式

对于每个询问指令 Q x,输出一个询问结果,如果 x 在集合中出现过,则输出 Yes,否则输出 No

每个结果占一行。

数据范围

1≤N≤1e5
−1e9≤x≤1e9

输入样例:
5
I 1
I 2
I 3
Q 2
Q 5
输出样例:
Yes
No
思路:

散列表的标准写法

代码:
//1e9+7这是一个质数
#include<bits/stdc++.h>

using namespace std;

//开放寻址发一般开成两倍
//找出200000之后第一个质数
/*
for(int i=2*1e5;;i++)
{
	bool flag=true;
	for(int j=2;j*j<=i;j++)
	{
		if(i%j==0)
		{
			flag=false;
			break;
		}
	}
	if(flag)
	{
		cout<<i;
		break;
	}
}
*/ 

const int N=200003,null=0x3f3f3f3f;
//一般设最大值都是0x3f3f3f3f,大约比1e9大一些 
//用null这个数表示位置上没有数字,null这个数字在题目给的数字范围之外,所以说不会引起错误
//如果设置的数在数字范围之内,可能会造成错误判断(本来没有这个数结果每个空位置都是这个数) 
int h[N];

//开放寻址法
int find(int x)
{
	int k=(x%N+N)%N;
	while(h[k]!=null && h[k]!=x)
	{
		k++;
		if(k==N)k=0;//后面都没有就从头开始找
	}	
	return k;
}

void insert(int x)
{
    int t=find(x);
	h[t]=x;
}

int main()
{
	int n;
	cin>>n;
	
	memset(h,0x3f,sizeof h);//memset是按照字节来set的,
	                        //比如说int是四个字节,则每个字节都是0x3f,即为0x3f3f3f3f
	
	while(n--)
	{
		char op[2];
		int x;
		cin>>op;
		cin>>x;
		if(*op=='I')
		{
			insert(x);
		}
		else
		{
			int k=find(x);
			if(h[k]!=null) cout<<"Yes"<<endl;
			else cout<<"No"<<endl;
		}
	}
	
	return 0;
}

3、字符串哈希(模板)

给定一个长度为 n 的字符串,再给定 m 个询问,每个询问包含四个整数 l1,r1,l2,r2,请你判断 [l1,r1]和 [l2,r2]这两个区间所包含的字符串子串是否完全相同。

字符串中只包含大小写英文字母和数字。

输入格式

第一行包含整数 n 和 m,表示字符串长度和询问次数。

第二行包含一个长度为 n 的字符串,字符串中只包含大小写英文字母和数字。

接下来 m 行,每行包含四个整数 l1,r1,l2,r2,表示一次询问所涉及的两个区间。

注意,字符串的位置从 1 开始编号。

输出格式

对于每个询问输出一个结果,如果两个字符串子串完全相同则输出 Yes,否则输出 No

每个结果占一行。

数据范围

1≤n,m≤1e5

输入样例:
8 3
aabbaabb
1 3 5 7
1 3 6 8
1 2 1 2
输出样例:
Yes
No
Yes
思路:

字符串哈希模板写法

代码:
#include<bits/stdc++.h>
using namespace std;

int n,m;

typedef unsigned long long  ULL;

const int N=100010,P=131;

char str[N];
ULL h[N],p[N];

//不能映射成0 
//假定不存在冲突的情况
//当p取131或1331的时候(这两个是经验值),q取成2的64次方,可以假定不会出现冲突(99.99%的情况下不会冲突)
//h[lr]=h[r]-h[l] * P**(l-r+1),为l到r之间的哈希值 
//9999 - 97*100
ULL get(int l,int r)
{
	return h[r]-h[l-1]*p[r-l+1];
}

int main()
{
	cin>>n>>m>>str+1;
	//预处理
	p[0]=1;
	for(int i=1;i<=n;i++)p[i]=p[i-1]*P; //每个位置的权重求出来 即为p的次方 
	for(int i=1;i<=n;i++)h[i]=h[i-1]*P + str[i];
	while(m--)
	{
		int l1,r1,l2,r2;
		cin>>l1>>r1>>l2>>r2;
		if (get(l1,r1)==get(l2,r2))cout<<"Yes"<<endl;
		else cout<<"No"<<endl; 
		
	}	
	
	return 0;
}

4、四平方和(第七届蓝桥杯省赛C++ A组/B组 & JAVA B组/C组)

四平方和定理,又称为拉格朗日定理:

每个正整数都可以表示为至多 4 个正整数的平方和。

如果把 0 包括进去,就正好可以表示为 4个数的平方和。

比如:

5=0**2+0**2+1**2+2**2
7=1**2+1**2+1**2+2**2

对于一个给定的正整数,可能存在多种平方和的表示法。

要求你对 4 个数排序:

0≤a≤b≤c≤d0

并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法。

输入格式

输入一个正整数 N。

输出格式

输出4个非负整数,按从小到大排序,中间用空格分开。

数据范围

0<N<5∗1e6

输入样例:
5
输出样例:
0 0 1 2
思路:

哈希加二分

代码:
//四平方和
//二分
#include<bits/stdc++.h>

using namespace std;

const int N = 5e6 + 10;

struct Sum{
    int s, c, d;
    bool operator<(const Sum &t)const
    {
        if(s != t.s) return s < t.s;
        if(c != t.c) return c < t.c;
        return d < t.d;
    }
};

int n;
Sum record[N * 2];

int main()
{
    cin >> n;

    int k = 0;
    for(int c = 0; c * c <= n; c++)
    {
        for(int d = c; c * c + d * d <= n; d ++)
        {
            record[k++] = {c * c + d * d, c, d};
        }
    }

    sort(record, record + k);

    for(int a = 0; a * a <= n; a ++)
    {
        for(int b = a; a * a + b * b <= n; b++)
        {
            int t = n - a * a - b * b;

            int l = 0, r = k - 1;
            while(l < r)
            {
                int mid = l + r >> 1;
                if(record[mid].s >= t) r = mid;
                else l = mid + 1;
            }

            if(record[l].s == t)
            {
                printf("%d %d %d %d\n", a, b, record[l].c, record[l].d);
                return 0;
            }
        }
    }
    return 0;
}

5、扫雷(Google Kickstart2014 Round C Problem A)

扫雷是一种计算机游戏,在 20 世纪 80 年代开始流行,并且仍然包含在某些版本的 Microsoft Windows 操作系统中。

在这个问题中,你正在一个矩形网格上玩扫雷游戏。

最初网格内的所有单元格都呈未打开状态。

其中 M 个不同的单元格中隐藏着 M 个地雷。

其他单元格内不包含地雷。

你可以单击任何单元格将其打开。

如果你点击到的单元格中包含一个地雷,那么游戏就会判定失败。

如果你点击到的单元格内不含地雷,则单元格内将显示一个 0 到 8 之间的数字(包括 0 和 8),这对应于该单元格的所有相邻单元格中包含地雷的单元格的数量。

如果两个单元格共享一个角或边,则它们是相邻单元格。

另外,如果某个单元格被打开时显示数字 0,那么它的所有相邻单元格也会以递归方式自动打开。

当所有不含地雷的单元格都被打开时,游戏就会判定胜利。

例如,网格的初始状态可能如下所示(* 表示地雷,而 c 表示第一个点击的单元格):

*..*...**.
....*.....
..c..*....
........*.
..........

被点击的单元格旁边没有地雷,因此当它被打开时显示数字 00,并且它的 88 个相邻单元也被自动打开,此过程不断继续,最终状态如下:

*..*...**.
1112*.....
00012*....
00001111*.
00000001..

此时,仍有不包含地雷的单元格(用 . 字符表示)未被打开,因此玩家必须继续点击未打开的单元格,使游戏继续进行。

你想尽快赢得游戏胜利并希望找到赢得游戏的最低点击次数。

给定网格的尺寸(N×N),输出能够获胜的最小点击次数。

输入格式

第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含整数 N,表示游戏网格的尺寸大小。

接下来 N 行,每行包含一个长度为 N 的字符串,字符串由 .(无雷)和 *(有雷)构成,表示游戏网格的初始状态。

输出格式

每组数据输出一个结果,每个结果占一行。

结果表示为 Case #x: y,其中 x 是组别编号(从 1 开始),y 是获胜所需的最小点击次数。

数据范围

1≤T≤100
1≤N≤300

输入样例:
2
3
..*
..*
**.
5
..*..
..*..
.*..*
.*...
.*...
输出样例:
Case #1: 2
Case #2: 8
思路:

预处出每个点的数字再对0的位置进行搜索,最后对漏网之鱼进行处理

代码:
#include<bits/stdc++.h>
using namespace std;
const int N =310;
int dx[8]={1,1,1,0,0,-1,-1,-1},dy[8]={1,0,-1,1,-1,1,0,-1};
int num[N][N],st[N][N];
char g[N][N];    //记录扫雷整张地图
void bfs(int a,int b,int n)   //寻找0点周围的所有点,标记为已遍历
{
    st[a][b]=1;
    num[a][b]=-1;

        for(int i=0;i<8;i++)
        {
            int x=a+dx[i],y=b+dy[i];
            if(x>=0 && x<n && y>=0 && y<n)
            {
                if(!st[x][y] && num[x][y]!=-1)
                {
                    if(num[x][y]>0) st[x][y]=1,num[x][y]=-1;
                    if(num[x][y]==0) bfs(x,y,n);
                }
            }
        }
}
int main()
{
    int T,n;
    scanf("%d",&T);
    for(int t=1;t<=T;t++)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%s",g[i]);

        memset(num,0,sizeof num);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(g[i][j]!='*')    //不是雷的要统计8个点上雷的总个数
                {
                    for(int k=0;k<8;k++)
                    {
                        int x=i+dx[k],y=j+dy[k];
                        if(x>=0 && x<n && y>=0 && y<n && g[x][y]=='*')
                        {
                            num[i][j]++;
                        }
                    }
                }
                else num[i][j]=-1;   //如果是雷则标记为-1
            }
        }

        memset(st,0,sizeof st);
        int ans=0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(num[i][j]==0 && !st[i][j])     //找到一个0点ans++,同时进行bfs
                {
                    ans++;  
                    bfs(i,j,n);
                }
            }
        }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
                if(num[i][j]!=-1 && !st[i][j]) ans++;  //找到漏网之鱼,每找到一个就ans++
        }
        printf("Case #%d: %d\n",t,ans);

    }
    return 0;
}

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

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

相关文章

【学习】软件测试行业未来的发展趋势预测

近年来&#xff0c;随着中国数字经济的蓬勃发展&#xff0c;软件测试行业也迎来了新的春天。从早期的手工测试到自动化测试&#xff0c;再到持续集成和持续交付&#xff0c;中国的软件测试行业经历了快速的发展和变革。各行各业均对软件测试提出了更高的要求&#xff0c;尤其在…

基于java+springboot+vue实现的大学生二手物品交易商城(文末源码+Lw+ppt)23-329

摘 要 二十一世纪我们的社会进入了信息时代&#xff0c;信息管理系统的建立&#xff0c;大大提高了人们信息化水平。传统的管理方式对时间、地点的限制太多&#xff0c;而在线管理系统刚好能满足这些需求&#xff0c;在线管理系统突破了传统管理方式的局限性。于是本文针对这…

暴雨讲堂:AI时代第五代英特尔CPU能做什么?

如果把科技圈比作娱乐圈&#xff0c;那么这两年的顶流一定是AI。2023年&#xff0c;世人见证了ChatGPT在全球范围内的大火&#xff0c;以生成式AI为代表的新一轮人工智能应用问世&#xff0c;改变了人工智能&#xff08;AI&#xff09;技术与应用的发展轨迹&#xff0c;并开始在…

展馆人数统计显示屏的功能分析

展馆人数统计显示屏是展览馆、博物馆、商场等公共场所常见的一种设备&#xff0c;它能够实时显示当前场馆内的人数信息&#xff0c;为管理者和游客提供重要参考。展馆人数统计显示屏的功能分析是对这一设备的作用、特点和优势进行深入剖析&#xff0c;有助于更好地了解其在实际…

音视频处理 - 音频概念详解,码率,采样率,位深度,声道,编码

1. 音频采样 与视频不同&#xff0c;音频的最小单位不是一帧&#xff0c;而是一个采样。 采样是当前一刻声音的声音样本&#xff0c;样本需要经过数字转换才能存储为样本数据。 真实声音是连续的&#xff0c;但是在计算机中&#xff0c;声音是离散且均匀的声音样本。 2. 位深…

【倪琴仲尼式-雷伴】全新倪诗韵精品杉木古琴

试音中的用弦&#xff1a;梦音&#xff0c;视频录音无任何处理&#xff0c;所见即所得。 现琴比照片更好看。倪琴吊牌、琴额后面的编码和倪琴官网上的序列号是一一对应的&#xff0c;可查。 雷伴&#xff0c;“伴”字取意陪伴、相伴、依随。栗壳色&#xff0c;纯鹿角霜生漆工艺…

反射率光纤光谱仪检测汽车后视镜反射率

反射率光纤光谱仪是一种用于测量材料表面反射率的精密仪器&#xff0c;它通过光纤传输光信号&#xff0c;并利用光谱仪进行分析&#xff0c;以确定材料的光学特性。反射率光纤光谱仪的工作原理基于相对反射率的计算&#xff0c;它涉及到光源、光纤、光谱仪等关键组件。 后视镜能…

使用ES5进行win10系统封装

一、概述 为什么那时候会折腾这个呢&#xff0c;因为我平时用的一般是PE或者直接刻录安装系统&#xff0c;但是这样类似于每次安装完系统后都需要进行一些优化设置&#xff0c;比如电源选项、资源管理器设置、办公软件安装等等&#xff0c;我也听说过ghost但是没有实际用过不过…

Apache Hive的部署与体验

一、Apache Hive概述 什么是分布式SQL计算&#xff1f; 以分布式的形式&#xff0c;执行SQL语句&#xff0c;进行数据统计分析。Apache Hive是做什么的&#xff1f; 很简单&#xff0c;将SQL语句翻译成MapReduce程序&#xff0c;从而提供用户分布式SQL计算的能力。传统MapRed…

[2023] 14届

1.日期统计 题意 1.日期统计 - 蓝桥云课 (lanqiao.cn) 思路 用dfs扫 对每一个位进行限制 花了一个小时 注意把答案枚举出来 对应一下看到底对不对 code #include<iostream> #include<cstdio> #include<stack> #include<vector> #include<al…

一文看懂算法交易(二)

国内T0算法哪家强&#xff1f;算法交易费用是多少&#xff1f;算法交易哪些平台好&#xff1f; 我们接上文今天给大家继续分享&#xff0c;我们昨天大致了解了什么是算法交易&#xff0c;国内的算法总线大概有些啥&#xff0c;算法交易的类型。那么我们今天再普及下&#xff0c…

neo4j使用详解(三、cypher插入语法——最全参考)

1.插入语法 create, merge, set, delete, remove, create unique, load csv(import) 除插入语法外另外的语法详情请博主其他文章&#xff1a; 查询语法 其他语法 1.1.create语法 创建单个节点: create(n) # (ID:n) 创建带标签的节点: create (n:Person) # (ID:n, label:Perso…

Tableau项目实战-网站流量统计分析

数据介绍 网站流量分析.xlsx 1、页面指标分析 页面指标主要有网站流量指标、用户行为指标、用户浏览网站的方式等。 页面访问次数 访客完整打开网站页面进行访问的次数,访问次数是网站访问速度的衡量标准。 平均停留的时间 平均访问时长是用户访问网站的平均停留时间。 …

力扣HOT100 - 42. 接雨水

解题思路&#xff1a; 动态规划 感觉不是很好想 class Solution {public int trap(int[] height) {int n height.length;if (n 0) return 0;int[] leftMax new int[n];leftMax[0] height[0];for (int i 1; i < n; i) {leftMax[i] Math.max(leftMax[i - 1], height[i…

基于Springboot Vue医院管理系统+数据库脚本+文档(万字)

项目效果视频: 基于Springboot Vue医院管理系统 一、 项目介绍 角色&#xff1a;管理员、患者、医生 基于springboot vue实现的医院管理系统&#xff0c;有管理员、医生和患者三种角色。系统拥有丰富的功能&#xff0c;能够满足各类用户的需求&#xff0c;系统提供了登录和注册…

javaWeb学生宿舍管理系统

一、摘要 本博客介绍了如何使用Spring Boot和MySQL构建一个功能完善的JavaWeb学生宿舍管理系统。该系统分为三个角色&#xff1a;管理员、宿管和学生。管理员拥有对整个系统的全面管理权限&#xff0c;包括学生管理、宿舍管理、入住管理和管理员管理&#xff1b;宿管负责宿舍的…

线上linux服务器升级nginx

一个nginx版本空包 一个pcre文件 一个zlib文件 ./configure配置文件 make编译 make install复制所有文件到nginx 如果nginx -v无版本号 检查环境变量cat /etc/profile 编辑 环境变量vi /etc/profile 按i进入编辑模式 按esc进入查看模式 因为path中并未使用%JAVA_HOME%字样…

QMT量化交易上手

文章目录 QMT介绍基本使用代码初始化股票和行情交易量化策略示例相关链接QMT介绍 QMT是迅投公司出品量化交易客户端软件,目前只能运行在windows机器上,分为QMT 和 miniQMT两种模式,后者可以采用python API做程序化交易,极大方便了广大散户。这点上比同花顺/通信达好很多。…

在 IntelliJ IDEA 中使用 Terminal 执行 git log 命令后的退出方法

前言 IntelliJ IDEA 是一款广受欢迎的集成开发环境&#xff0c;它内置了强大的终端工具&#xff0c;使得开发者无需离开IDE就能便捷地执行各种命令行操作&#xff0c;包括使用 Git 进行版本控制。在 IDEA 的 Terminal 中执行 git log 命令时&#xff0c;由于该命令会显示项目的…

微信登录开发

1、h5页面增加一个微信登录&#xff0c;省去手机号验证码登录的繁琐。 首先需要开通服务号&#xff0c;我用的是公司的服务号&#xff0c;开发的小伙伴可以去找领导开通。开通后把自己的微信号加进去就可以进行下面的步骤了。 在微信开发者平台上的公众号设置中去设置业务域名、…