AcWing 2060. 奶牛选美(dfs+详细说明)

一、题目

听说最近两斑点的奶牛最受欢迎,约翰立即购进了一批两斑点牛。

不幸的是,时尚潮流往往变化很快,当前最受欢迎的牛变成了一斑点牛。

约翰希望通过给每头奶牛涂色,使得它们身上的两个斑点能够合为一个斑点,让它们能够更加时尚。

牛皮可用一个 N×M 的字符矩阵来表示,如下所示:

................
..XXXX....XXX...
...XXXX....XX...
.XXXX......XXX..
........XXXXX...
.........XXX....

其中,X 表示斑点部分。

如果两个 X 在垂直或水平方向上相邻(对角相邻不算在内),则它们属于同一个斑点,由此看出上图中恰好有两个斑点。

约翰牛群里所有的牛都有两个斑点

约翰希望通过使用油漆给奶牛尽可能少的区域内涂色,将两个斑点合为一个。

在上面的例子中,他只需要给三个 .. 区域内涂色即可(新涂色区域用 ∗ 表示):

................
..XXXX....XXX...
...XXXX*...XX...
.XXXX..**..XXX..
........XXXXX...
.........XXX....

 

请帮助约翰确定,为了使两个斑点合为一个,他需要涂色区域的最少数量。

输入格式

第一行包含两个整数 N 和 M。

接下来 N 行,每行包含一个长度为 M 的由 X 和 .. 构成的字符串,用来表示描述牛皮图案的字符矩阵。

输出格式

输出需要涂色区域的最少数量。

数据范围

1≤N,M≤50

输入样例:
6 16
................
..XXXX....XXX...
...XXXX....XX...
.XXXX......XXX..
........XXXXX...
.........XXX....
输出样例:
3

二、题目分析 

分析

根据题意来看很容易判断出可以用dfs或bfs来解决,我是选用的dfs。

首先,题目中明确说明了,约翰牛群里所有的牛都有两个斑点,即有两量组不连通的X。题目要求是求涂色区域的最少数量。很容易看出,最少数量=两边X之间的最小的曼哈顿距离-1(二维空间,曼哈顿距离d = |x1 - x2| + |y1 - y2|),所以题目转变为去求曼哈顿距离。

那我们可以定义两个容器,分别存放两组X的坐标。而后遍历两组坐标,求出最小的曼哈顿距离。

步骤1

dfs将两组X坐标分别放入两个容器

步骤2

遍历容器求最小的曼哈顿距离

步骤3

给求到的最小曼哈顿距离-1并输出

三、代码

#include<bits/stdc++.h>
using namespace std;
const int N=60;
char a[N][N];
typedef pair<int,int>pii;
vector<pii> p[2];//存放两组X的坐标
int n,m;
int dx[4]={0,0,1,-1};//偏移量,即在搜索过程中,控制坐标只能在上下左右移动一个单位
int dy[4]={1,-1,0,0};
bool check(int x,int y){//判断坐标是否越界
    if(x>n||y>m||x<1||y<1) return false;
    else return true;
}
void dfs(int x,int y,vector<pii> &pp){
    if(!check(x,y)) return ;
    if(a[x][y]=='.') return ;
    else{
        a[x][y]='.';//把X变成.这样在主函数的双重循环中,dfs只会进入两次,每一次都会把一组X坐标存入,并且把这一组的X全变为.
        pp.push_back({x,y});
        for(int i=0;i<4;i++){
            int tx=x+dx[i],ty=y+dy[i];
            dfs(tx,ty,pp);
        }
    }
}

int main(){
    int k=0;//表示使用的是第几个容器,因为只有两组X,所以k的值只会是0,1
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i][j]=='X'){
                dfs(i,j,p[k++]);
            }
        }
    }

    int ans=120;//存放最小曼哈顿距离,初始化值必须大于左上的坐标与右下坐标的曼哈顿距离,即大于98
    for(int i=0;i<p[0].size();i++){
        for(int j=0;j<p[1].size();j++){
            ans=min(ans,(abs(p[0][i].first-p[1][j].first)+abs(p[0][i].second-p[1][j].second)));//求曼哈顿距离,并与当前最小值比较
        }
    }
    cout<<ans-1;
}

  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值