#E. Cow Art(bfs经典习题)

该文描述了一个编程问题,涉及计算由人类和红绿色盲的奶牛观察的彩色方格图案中不同区域的数量。通过两次使用广度优先搜索(BFS)算法,分别计算人和奶牛看到的连通块,其中奶牛将红色和绿色视为同一种颜色。问题提供了一种解决方案,包括输入处理、两次BFS实现及边界条件判断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

说明

一个有关奶牛的鲜为人知的事实是她们都是红绿色盲,也就是说,在她们看来,红色和绿色是一样的(译者注:奶牛把这种颜色称作“红绿色”)。这使得我们设计的艺术作品难以同时符合人类和奶牛的审美口味。考虑一个由N x N格字符表示的方形绘画作品,其中每个字符为R(红),G(绿)或者B(蓝)。一幅绘画如果有许多互不相同的着色“区域”,则我们认为它是有趣的。如果两个字符是直接相邻的(一个在另一个的东、南、西、北方向)且其表示的颜色相同,则这两个字符属于同一个区域。例如,下面这幅绘画作品:

RRRBB

GGBBB

BBBRR

BBRRR

RRRRR

如果由人类来看有4个区域(2个红色,1个蓝色和1个绿色区域),而如果由奶牛来看则只有3个区域(2个红绿色,1个蓝色区域)。现给你一副绘画作为输入,请计算该作品由人类和奶牛来看分别有多少个区域。

输入格式

第1行:整数N(N<=100)。

第2..1+N行:每行包含一个长度为N的字符串,表示绘画作品的一行。

输出格式

第1行:两个空格隔开的整数,分别给出由人类和奶牛欣赏绘画作品时会看见多少个区域。

样例

输入数据 1

5

RRRBB

GGBBB

BBBRR

BBRRR

RRRRR

输出数据 1

4 3


思路

做这道题目前建议先做做一本通P1329细胞,因为这题是细胞的举一反三。

主函数逻辑

先设数组visvis[i][j] == 1表示(i,j)位置已经访问过

然后2次搜索连通块数量(第一次是人,第二次是奶牛)

每次都是遍历地图中的每个位置,从每个位置开始进行搜索

遍历网格的过程中,一次成功开始的搜索可以确定一个连通块,统计连通块个数,即为结果。

主函数:

int main()
{
  cin>>n;
  m = n;
  for(int i = 0; i < n; i++)
  {
    for(int j = 0; j < n; j++)
    {
      cin>>a[i][j];
    }
  }
//以人来看有多少连通块
  for(int i = 0; i < n; i++)
  {
    for(int j = 0; j < m; j++)
    {
      if(vis[i][j] == 0)//如果该位置没有访问过,那么访问该位置,并bfs。
      {
        colour++;
        bfs(i,j);
      }
    }
  }
  cout<<colour<<' ';
  memset(vis,0,sizeof(vis));//因为后面还有bfs以奶牛来看有多少连通块,所以要初始化
  colour = 0;
  for(int i = 0; i < n; i++)
  {
    for(int j = 0; j < m; j++)
    {
      if(vis[i][j] == 0)//跟以人来看同理(就是bfs变成了bfs_2)
      {
        colour++;
        bfs_2(i,j);
      }
    }
  }
  cout<<colour;
  return 0;
}

2次bfs函数逻辑

bfs(ren)跟普通bfs差不多,就是判断能不能将现搜到的点加进队列中的条件变了:

nd.x >= 0 && nd.x < n && nd.y >= 0 && nd.y < m 
&& a[nd.x][nd.y] == a[t.x][t.y] && vis[nd.x][nd.y] == 0

也就是判断现在搜到的点是否没有越界,且搜到的点走到搜到的点的点是否相同,且没走过

但是bfs_2(奶牛)的判断条件就又变了一下:

if(nd.x >= 0 && nd.x < n && nd.y >= 0 && nd.y < m && (a[nd.x][nd.y] == a[t.x][t.y] || (a[nd.x][nd.y] == 'R' && a[t.x][t.y] == 'G') || (a[nd.x][nd.y] == 'G' && a[t.x][t.y] == 'R')) && vis[nd.x][nd.y] == 0)

也就是判断现在搜到的点是否没有越界,且(搜到的点走到搜到的点的点是否相同或者这2个点一个R,一个数G(因为奶牛是红绿色盲)),且没走过

2次bfs:

void bfs(int x,int y)
{
  dot t;
  t.x = x;
  t.y = y;
  q.push(t);
  while(!q.empty())
  {
    t = q.front();
    for(int i = 0; i < 4; i++)
    {
      dot nd = t;
      nd.x = nd.x + dx[i];
      nd.y = nd.y + dy[i];
      if(nd.x >= 0 && nd.x < n && nd.y >= 0 && nd.y < m && a[nd.x][nd.y] == a[t.x][t.y] && vis[nd.x][nd.y] == 0)
      {
        q.push(nd);
        vis[nd.x][nd.y] = colour;
      }
    }
    q.pop();
  }
}
void bfs_2(int x,int y)
{
  dot t;
  t.x = x;
  t.y = y;
  q.push(t);
  while(!q.empty())
  {
    t = q.front();
    for(int i = 0; i < 4; i++)
    {
      dot nd = t;
      nd.x = nd.x + dx[i];
      nd.y = nd.y + dy[i];
      if(nd.x >= 0 && nd.x < n && nd.y >= 0 && nd.y < m && (a[nd.x][nd.y] == a[t.x][t.y] || (a[nd.x][nd.y] == 'R' && a[t.x][t.y] == 'G') || (a[nd.x][nd.y] == 'G' && a[t.x][t.y] == 'R')) && vis[nd.x][nd.y] == 0)
      {
        q.push(nd);
        vis[nd.x][nd.y] = colour;
      }
    }
    q.pop();
  }
}

代码

#include <bits/stdc++.h>
using namespace std;
int n,m;//行 列
char a[1000][1000];
int vis[1000][1000];
int dx[4]= {-1,0,1,0},dy[4]= {0,1,0,-1};
int colour;
struct dot
{
  int x,y;
};
queue<dot>q;
void bfs(int x,int y)
{
  dot t;
  t.x = x;
  t.y = y;
  q.push(t);
  while(!q.empty())
  {
    t = q.front();
    for(int i = 0; i < 4; i++)
    {
      dot nd = t;
      nd.x = nd.x + dx[i];
      nd.y = nd.y + dy[i];
      if(nd.x >= 0 && nd.x < n && nd.y >= 0 && nd.y < m && a[nd.x][nd.y] == a[t.x][t.y] && vis[nd.x][nd.y] == 0)
      {
        q.push(nd);
        vis[nd.x][nd.y] = colour;
      }
    }
    q.pop();
  }
}
void bfs_2(int x,int y)
{
  dot t;
  t.x = x;
  t.y = y;
  q.push(t);
  while(!q.empty())
  {
    t = q.front();
    for(int i = 0; i < 4; i++)
    {
      dot nd = t;
      nd.x = nd.x + dx[i];
      nd.y = nd.y + dy[i];
      if(nd.x >= 0 && nd.x < n && nd.y >= 0 && nd.y < m && (a[nd.x][nd.y] == a[t.x][t.y] || (a[nd.x][nd.y] == 'R' && a[t.x][t.y] == 'G') || (a[nd.x][nd.y] == 'G' && a[t.x][t.y] == 'R')) && vis[nd.x][nd.y] == 0)
      {
        q.push(nd);
        vis[nd.x][nd.y] = colour;
      }
    }
    q.pop();
  }
}
int main()
{
  cin>>n;
  m = n;
  for(int i = 0; i < n; i++)
  {
    for(int j = 0; j < n; j++)
    {
      cin>>a[i][j];
    }
  }
  for(int i = 0; i < n; i++)
  {
    for(int j = 0; j < m; j++)
    {
      if(vis[i][j] == 0)
      {
        colour++;
        bfs(i,j);
      }
    }
  }
  cout<<colour<<' ';
  memset(vis,0,sizeof(vis));
  colour = 0;
  for(int i = 0; i < n; i++)
  {
    for(int j = 0; j < m; j++)
    {
      if(vis[i][j] == 0)
      {
        colour++;
        bfs_2(i,j);
      }
    }
  }
  cout<<colour;
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值