蓝桥杯刷题第二十三天

时间:2021-10-13 01:19:27

第一题:长草

题目描述
小明有一块空地,他将这块空地划分为 nm 列的小块,每行和每列的长度都为 1。
小明选了其中的一些小块空地,种上了草,其他小块仍然保持是空地。
这些草长得很快,每个月,草都会向外长出一些,如果一个小块种了草,则它将向自己的上、下、左、右四小块空地扩展,
这四小块空地都将变为有草的小块。请告诉小明,k 个月后空地上哪些地方有草。
输入描述
输入的第一行包含两个整数 n,m
接下来 n 行,每行包含 m 个字母,表示初始的空地状态,字母之间没有空格。如果为小数点,表示为空地,如果字母为 g,表示种了草。
接下来包含一个整数 k。 其中 2≤n,m≤1000,1≤k≤1000。
输出描述
输出 n 行,每行包含 m 个字母,表示 k 个月后空地的状态。如果为小数点,表示为空地,如果字母为 g,表示长了草。

dfs,对每个当前层的g进行长草,并且长出来的草都是下一层可以长的草

这样就可以确保每一层只对当前层进行操作

当然全变为g了,就不用继续了,直接break,这里要进行一下特判就行

好像不加也可以过,数据,,,

#include<iostream>
using namespace std;

const int N = 1010;
int n, m, k;
int ed[N][N];
char st[N][N];

bool check(){
  for(int i = 1; i <= n; i++)
    for(int j = 1; j <= m; j++)
      if(ed[i][j] == 0)  return true;
  return false;
}

void dfs(int u, int v, int d){
  int dx[] = {0, 0, -1, 1};
  int dy[] = {1, -1, 0, 0};
  for(int i = 0; i < 4; i++){
    int x = dx[i] + u, y = dy[i] + v;
    if(x >= 1 && y >= 1 && x <= n && y <= m && st[x][y] == '.'){
      st[x][y] = 'g';
      ed[x][y] = d;
    }
  }
}


int main(){
  scanf("%d%d", &n, &m);

  for(int i = 1; i <= n; i++)
    for(int j = 1; j <= m; j++){
      cin>>st[i][j];
      ed[i][j] = 1;
    }

  scanf("%d", &k);

  int x = 1;   //第一层
  while(x <= k){
    if(check()) break;   //全变为g不用再搜索了
    for(int i = 1; i <= n; i++)
      for(int j = 1; j <= m; j++)
        if(st[i][j] == 'g' && ed[i][j] == x)
          dfs(i, j, x + 1);
    x++;
  }

  for(int i = 1; i <= n; i++){
    for(int j = 1; j <= m; j++)
      printf("%c", st[i][j]);
    puts("");
  }
  return 0;
}

第二题:蓝肽子序列

题目描述
L 星球上的生物由蛋蓝质组成,每一种蛋蓝质由一类称为蓝肽的物资首尾连接成一条长链后折叠而成。
生物学家小乔正在研究 L 星球上的蛋蓝质。她拿到两个蛋蓝质的蓝肽序列,想通过这两条蓝肽序列的共同特点来分析两种蛋蓝质的相似性。
具体的,一个蓝肽可以使用 1 至 5 个英文字母表示,其中第一个字母大写,后面的字母小写。一个蛋蓝质的蓝肽序列可以用蓝肽的表示顺序拼接而成。
在一条蓝肽序列中,如果选取其中的一些位置,把这些位置的蓝肽取出,并按照它们在原序列中的位置摆放,则称为这条蓝肽的一个子序列。蓝肽的子序列不一定在原序列中是连续的,中间可能间隔着一些未被取出的蓝肽。
如果第一条蓝肽序列可以取出一个子序列与第二条蓝肽序列中取出的某个子序列相等,则称为一个公共蓝肽子序列。
给定两条蓝肽序列,找出他们最长的那个公共蓝肽子序列的长度。
输入描述
输入两行,每行包含一个字符串,表示一个蓝肽序列。字符串中间没有空格等分隔字符。
其中有 ,两个字符串的长度均不超过 1000。
输出描述
输出一个整数,表示最长的那个公共蓝肽子序列的长度。

最长公共子序列问题

f[i, j] 表示从a里面选前i个数,和从b里面选前j个数,构成的最长长度

  1. a[i] != b[j] f[i][j] = max(f[i-1][j], f[i][j-1]), 等于最大的a上一个长度,或者b上一个长度

  1. a[i] == b[j] f[i][j] = max(f[i][j], f[i-1][j-1] + 1), 等于最大的本身和a,b上一个加一

现在问题是怎么变成蓝肽,去比较大小

遍历字符串,如果不是第一个字符,而且是大写 就把前面的字符形成的串加进去

如果是最后一个字符,而且是小写 当前字符加进去,然后再break

除了第二个如果情况,其余都要加进当前子字符

注意保存长度,和初始化一些值,因为没有封装成函数

#include<iostream>
#include<vector>
using namespace std;

const int N = 1010;
string a[N], b[N];
int f[N][N];

int main(){
  string s1, s2;
  cin>>s1; cin>>s2;

  string str = "";
  int n = s1.size(), m = s2.size();
  int k = 1;
  for(int i = 0; i < n; i++){
    if(i > 0 && s1[i] >= 'A' && s1[i] <= 'Z'){
      a[k++] = str;
      str = "";
    }
    if(i == n - 1) {
      str += s1[i];
      a[k++] = str;
      str = "";
      break;
    }
    str += s1[i];
  }
  n = k - 1;

  k = 1;
  for(int i = 0; i < m; i++){
    if(i > 0 && s2[i] >= 'A' && s2[i] <= 'Z'){
      b[k++] = str;
      str = "";
    }
    if(i == m - 1) {
      str += s2[i];
      b[k++] = str;
      str = "";
      break;
    }
    str += s2[i];
  }
  m = k - 1;

  for(int i = 1; i <= n; i++)
    for(int j = 1; j <= m; j++){
      f[i][j] = max(f[i-1][j], f[i][j-1]);
      if(a[i] == b[j]) f[i][j] = max(f[i][j], f[i-1][j-1] + 1);
    }

  cout<<f[n][m]<<endl;
  return 0;
}

第三题:迷宫与陷阱

题目描述
小明在玩一款迷宫游戏,在游戏中他要控制自己的角色离开一间由 N×N 个格子组成的 2D 迷宫。
小明的起始位置在左上角,他需要到达右下角的格子才能离开迷宫。
每一步,他可以移动到上下左右相邻的格子中(前提是目标格子可以经过)。
迷宫中有些格子小明可以经过,我们用 '.' 表示。
有些格子是墙壁,小明不能经过,我们用 '#' 表示。
此外,有些格子上有陷阱,我们用 'X' 表示。除非小明处于无敌状态,否则不能经过。
有些格子上有无敌道具,我们用 '%' 表示。
当小明第一次到达该格子时,自动获得无敌状态,无敌状态会持续 K 步。
之后如果再次到达该格子不会获得无敌状态了。
处于无敌状态时,可以经过有陷阱的格子,但是不会拆除/毁坏陷阱,即陷阱仍会阻止没有无敌状态的角色经过。
给定迷宫,请你计算小明最少经过几步可以离开迷宫?
输入描述
输入描述
第一行包含两个整数 N,K (1≤N≤1000,1≤K≤10)。
以下 N 行包含一个 N×N 的矩阵。
矩阵保证左上角和右下角是 '.'。
输出描述
一个整数表示答案。如果小明不能离开迷宫,输出 -1。

只过了60%,不知道为啥

跟迷宫问题差不多,加了个无敌状态

而且要用到当层的无敌状态,这就要创建结构体以及数组来确定了

其余的就是bfs

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;

const int N = 1010;
int d[N][N], vis[N][N][15];
int n, k;
char g[N][N];
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
struct node{
  int x, y, k;
  node (int ax, int ay, int ak){
    x = ax, y = ay, k = ak;
  }
};

int bfs(){
  queue<node> q;
  vis[1][1][0] = 1;
  q.push({1, 1, 0});

  while(!q.empty()){
      auto t = q.front();
      q.pop();
      if(t.x == n && t.y == n)
        return d[n][n];
      for(int i = 0; i < 4; i++){
        int x = dx[i] + t.x, y = dy[i] + t.y;
        if(x < 1 || x > n && y < 1 || y > n || g[x][y] == '#') continue;

        if(g[x][y] == '%' && !vis[x][y][k]){
          vis[x][y][k] = 1;
          d[x][y] = d[t.x][t.y] + 1;
          q.push(node{x, y, k});
        } 
        else{
          if(t.k && !vis[x][y][t.k - 1]){
            vis[x][y][t.k - 1] = 1;
            d[x][y] = d[t.x][t.y] + 1;
            q.push(node{x, y, t.k - 1});
          }
          else if(g[x][y] == '.' && !t.k && !vis[x][y][0]){
            vis[x][y][0] = 1;
            d[x][y] = d[t.x][t.y] + 1;
            q.push(node{x, y, 0});
          }
        }
      }
  }

  return -1;
}

int main(){
  scanf("%d%d", &n, &k);

  for(int i = 1; i <= n; i++) 
    for(int j = 1; j <= n; j++)
      cin>>g[i][j];

  cout<<bfs()<<endl;
  return 0;
}