洛谷题单- 全球变暖,迷宫与陷阱,字符串哈希表

P8662 [蓝桥杯 2018 省 AB] 全球变暖

题目描述

你有一张某海域 N×N 像素的照片,. 表示海洋、 # 表示陆地,如下所示:

.......
.##....
.##....
....##.
..####.
...###.
.......

其中 "上下左右" 四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 22 座岛屿。

由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。

例如上图中的海域未来会变成如下样子:

.......
.......
.......
.......
....#..
.......
.......

请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。

输入格式

第一行包含一个整数 N.(1≤N≤1000)。

以下 N 行 N 列代表一张海域照片。

照片保证第 11 行、第 11 列、第 N 行、第 N 列的像素都是海洋。

输出格式

一个整数表示答案。

输入输出样例

输入 #1复制

7 
.......
.##....
.##....
....##.
..####.
...###.
.......  

输出 #1复制

1

说明/提示

时限 1 秒, 256M。蓝桥杯 2018 年第九届省赛

这个题说明一下,先进行一遍dfs统计总数的岛屿,只需把周围是海洋的陆地覆盖一下,剩下的陆地就是还没完全淹没的岛屿,还有连在一起的陆地就是一个岛屿了,当时一直纠结上下左右连在一块的是岛屿,还有考虑的地方是把每个岛屿用另外一个字符围起来,表示它是单独的岛屿(去重)避免算到同一个岛屿上去。废话不多说,上代码。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int next[4][2]={0,1,
                1,0,
                0,-1,
                -1,0
                 };
char a[1005][1005],b[1005][1005];
book[1005][1005];
int n;
int summ;
void dfs(int x,int y,int num)//海洋覆盖一个单位
{   if(num==1)
    {b[x][y]='.';
    for(int i=0;i<4;i++)
   {
     int tx,ty;
       tx=x+next[i][0];
       ty=y+next[i][1];
       if(tx<0||ty<0||tx>n-1||ty>n-1)
        continue;
       if(b[tx][ty]=='#')
       {
           dfs(tx,ty,num);
       }
   }
   }
    else
    {
        a[x][y]='.';
      for(int i=0;i<4;i++)
     {
     int tx,ty;
       tx=x+next[i][0];
       ty=y+next[i][1];
       if(tx<0||ty<0||tx>n-1||ty>n-1)
        continue;
       if(a[tx][ty]!='.')
       {
           dfs(tx,ty,num);
       }
      }
    }
}
int pd(int x,int y)
{
    for(int i=0;i<4;i++)//判断周围是否有海洋
    {
            int tx,ty;
        tx=x+next[i][0];
        ty=y+next[i][1];
        if(a[tx][ty]=='.')
            return 1;
    }
    return 0;
}
int main()
{
   int sum=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
       {
           scanf("%s",a[i]);
           strcpy(b[i],a[i]);
       }
    for(int i=0;i<n;i++)//对所有的岛屿进行统计
    {
        for(int j=0;j<n;j++)
        {
            if(b[i][j]=='#')
            {   summ++;
                dfs(i,j,1);
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(a[i][j]=='#')对没个岛屿的周围用另外一个字符代替
            {
               if(pd(i,j))
                  a[i][j]='|';
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(a[i][j]=='#')//对没有淹没的到进行计数
            {
               sum++;
               dfs(i,j,0);
            }
        }
    }
//    for(int i=0;i<n;i++)
//        printf("%s\n",a[i]);
  printf("%d",summ-sum);
    return 0;
}

P8673 [蓝桥杯 2018 国 C] 迷宫与陷阱 

题目描述

小明在玩一款迷宫游戏,在游戏中他要控制自己的角色离开一间由 N×N 个格子组成的二维迷宫。

小明的起始位置在左上角,他需要到达右下角的格子才能离开迷宫。

每一步,他可以移动到上下左右相邻的格子中(前提是目标格子可以经过)。

迷宫中有些格子小明可以经过,我们用 . 表示;

有些格子是墙壁,小明不能经过,我们用 # 表示。

此外,有些格子上有陷阱,我们用 X 表示。除非小明处于无敌状态,否则不能经过。

有些格子上有无敌道具,我们用 % 表示。

当小明第一次到达该格子时,自动获得无敌状态,无敌状态会持续 K 步。

之后如果再次到达该格子不会获得无敌状态了。

处于无敌状态时,可以经过有陷阱的格子,但是不会拆除 / 毁坏陷阱,即陷阱仍会阻止没有无敌状态的角色经过。

给定迷宫,请你计算小明最少经过几步可以离开迷宫。

输入格式

第一行包含两个整数 �N 和 �K。(1≤N≤1000,1≤K≤10)。

以下 N 行包含一个N×N 的矩阵。

矩阵保证左上角和右下角是 .

输出格式

一个整数表示答案。如果小明不能离开迷宫,输出 −1−1。

输入输出样例

输入 #1复制

5 3
...XX
##%#.
...#.
.###.
.....

输出 #1复制

10

输入 #2复制

5 1
...XX
##%#.
...#.
.###.
.....

输出 #2复制

12

说明/提示

时限 3 秒, 256M。蓝桥杯 2018 年第九届国赛

 这是一道bfs模版题,与其他不同的是,如何处理道具的问题,我们看看代码如何实现。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
struct note
{
    int x,y;
    int step,wd;
}que[10001000];
char a[1005][1005];
int vis[1005][1005];
int n,k;
int now;
int next1[4][2]={0,1,
                1,0,
                0,-1,
                -1,0
                 };
int main()
{
    memset(vis,-1,sizeof(vis));
    int head,tail;
    head=tail=0;
    que[tail].x=1;
    que[tail].y=1;
    que[tail].step=0;
    tail++;
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        cin>>a[i]+1;
    while(head<tail)
    {
        for(int i=0;i<4;i++)
        {
            int tx,ty;
            tx=que[head].x+next1[i][0];
            ty=que[head].y+next1[i][1];
            if(tx==n&&ty==n)
            {
                cout<<que[head].step+1;
                return 0;
            }
            if(tx<1||ty<1||tx>n||ty>n)
                continue;
                if(a[tx][ty]=='X'&&que[head].wd==0)
                    continue;
                    now=0>que[head].wd-1?0:que[head].wd-1;
                if(a[tx][ty]=='%')
                {
                  now=k;
                }
            if(a[tx][ty]!='#'&&vis[tx][ty]<now)
            {   vis[tx][ty]=now;
                que[tail].x=tx;
                que[tail].y=ty;
                que[tail].step=que[head].step+1;
                que[tail].wd=now;
                tail++;
            }

        }
        head++;
    }
    cout<<-1;
    return 0;
}

 

 P3370 【模板】字符串哈希

题目描述

如题,给定 N 个字符串(第 i 个字符串长度为 Mi​,字符串内包含数字、大小写字母,大小写敏感),请求出 N 个字符串中共有多少个不同的字符串。

友情提醒:如果真的想好好练习哈希的话,请自觉。

输入格式

第一行包含一个整数 N,为字符串的个数。

接下来 N 行每行包含一个字符串,为所提供的字符串。

输出格式

输出包含一行,包含一个整数,为不同的字符串个数。

输入输出样例

输入 #1复制

5
abc
aaaa
abc
abcc
12345

输出 #1复制

4

说明/提示

对于 30%30% 的数据:N≤10,Mi​≈6,Mmax≤15。

对于 70%70% 的数据N≤1000,Mi​≈100,Mmax≤150。

对于 100%100% 的数据:N≤10000,Mi​≈1000,����≤1500Mmax≤1500。

样例说明:

样例中第一个字符串(abc)和第三个字符串(abc)是一样的,所以所提供字符串的集合为{aaaa,abc,abcc,12345},故共计4个不同的字符串。

 

 这是一道哈希表的模拟题,之前我们说了哈希表的功能是检索速度非常快的一种数据结构,但是它也有缺点,就比如所orzc的哈希值是233,而orzhjw的哈希值也是233,这种情况称为哈希冲突,为了解决哈希冲突,有许多方法,比如拉链法,开放地址法等等,我们这里用进制哈希来解决这种问题,首先我们先定义个进制数base,然后对字符串进行运算。看看代码吧。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
char a[1505];
long long hash_[10005];
int n;
int base=19;
unsigned long long Hash(char *s)
{
    int len=strlen(s);
    unsigned long long sum=0;
     for(int i=0;i<len;i++)
     {
         sum=base*sum+(unsigned long long)+s[i];//这里进行了数据的溢出,太玄学了
     }
     return sum;
}
int main()
{
    int m;
    cin>>n;
    m=n;
    for(int i=0;i<m;i++)
    {
        cin>>a;
        hash_[i]=Hash(a);
         //cout<<mod(len)<<' ';
    }
    sort(hash_,hash_+n);
    long long ans=0;
    for(int i=0;i<n-1;i++)
    {
        if(hash_[i]!=hash_[i+1])
            ans++;
    }
    cout << ans+1 << endl;
    return 0;
}

 

  • 40
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值