【每日一题】【图论 遍历】RC-u3 暖炉与水豚 C++

2024 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(省赛)

RC-u3 暖炉与水豚

题目描述

PapiCon(@PapilloteContet)出了许多有意思的谜题,其中有一道关于水豚的谜题是这样的:

来源:x.com/PapilloteContet

在一个 N × M N×M N×M 的矩阵中有若干水豚以及暖炉,暖炉可以辐射以它自身为中心的 3 × 3 3×3 3×3 范围里的水豚,使其变得暖呼呼的。谜题里存在一只冷的要命的水豚,你需要移动其中的一个暖炉,使所有水豚都变得暖呼呼的。

在往下读题前,如果你有兴趣的话,不妨思考一下如何解答这个谜题。(思考结果与题目无关,可跳过。)

这个谜题的关键在于,单纯从图中能看到的暖炉来说是无解的,但如果注意到,第 3 3 3行第 6 6 6列的水豚明明周围没有暖炉,却也处于暖呼呼的状态,就能推测出来图中的那个对话框挡住了一个暖炉,只要移动这个暖炉就可以完成题目的要求。

现在我们将谜题一般化,对于给定的一个 N × M N×M N×M 的矩阵、对应的所有水豚状态、以及能看到的暖炉摆放情况,已知最多只有一只水豚的状态不太对劲(周围没有暖炉却暖呼呼的),你需要推测有哪些格子可能藏了暖炉。一个空格可能藏了暖炉可以理解为:当前空格设置暖炉后整个矩阵的状态会从不合法变为合法。

输入格式

输入第一行是两个正整数 N , M ( 1 ≤ N , M ≤ 1000 ) N, M (1≤N,M≤1000) N,M(1N,M1000),表示矩阵的大小。

接下来的 N N N行,每行有 M M M个字符,第 i i i行的第 j j j个字符表示矩阵中对应位置的状态,其中:

. 表示空格(或者说,看上去是空格的格子);
c 表示很冷的水豚;
w 表示暖呼呼的水豚;
m 表示暖炉。

输出格式

输出若干行,每行两个正整数 r r r c c c,表示第 r r r行第 c c c列有可能藏了一个暖炉,有多个可能时,先按 r r r从小到大输出, r r r相同时再按 c c c从小到大输出。如果没有一个格子可能藏了暖炉, 则在一行中输出Too cold!。
行与列均从 1 1 1开始编号。

样例 #1

样例输入 #1

6 8
wm....mw
.w..ww..
..wm.wwm
w.w....w
.m.c.m..
w.....w.

样例输出 #1

2 7
3 5
4 6
4 7

提示

代码长度限制 16 KB

Java (javac)
时间限制 800 ms
内存限制 256 MB

其他编译器
时间限制 400 ms
内存限制 64 MB
栈限制 8192 KB

做题要点

  1. 最多只有一只水豚的状态不太对劲(周围没有暖炉却暖呼呼的)
  2. 很冷的水豚不止一只
  3. 一个空格可能藏了暖炉
  4. 当前空格设置暖炉后整个矩阵的状态会从不合法变为合法
  5. 如果没有一个格子可能藏了暖炉, 则在一行中输出Too cold!。

做题思路

暖炉周围的水豚是正常的,那么反过来水豚周围没有暖炉是不正常的
那么不正常的水豚周围8格如果是空格那么就可能藏了暖炉
但有很冷的水豚,表示该水豚周围必定是没有暖炉的

总思路

  1. 找到所有很冷的水豚,去掉旁边的空格(做标记…),以免答案误入
  2. 遍历所有水豚,如果周围没有暖炉,记为并不正常,并且从上到下从左到右依次输出周围空格的下标

时间复杂度分析

  1. 遍历输入 O ( N × M ) O(N\times M) O(N×M)
  2. 去掉空格 O ( 9 × N × M ) O(9\times N\times M) O(9×N×M)
  3. 寻找不太对劲水豚 O ( N × M + 9 ) O(N\times M + 9) O(N×M+9)

总时间复杂度为 O ( 9 N × M ) O(9N\times M) O(9N×M)约为 1 0 7 10^7 107

伪代码

在这里插入图片描述

VJ赛时AC代码

#include <iostream>
using namespace std;
const int N = 1E3+10;
int n,m;
char a[N][N];
int cnt = 0;
bool check(int x,int y){
    for(int i=max(x-1,1);i<=x+1&&i<=n;i++){
        for(int j=max(y-1,1);j<=y+1&&j<=m;j++){
            if(a[i][j] == 'm')return false;
        }
    }
    return true;
}
void f(int x,int y){
    for(int i=max(x-1,1);i<=x+1&&i<=n;i++){
        for(int j=max(y-1,1);j<=y+1&&j<=m;j++){
            if(a[i][j] == '.'&&++cnt)
                cout << i << ' ' << j << '\n';
        }
    }
}
void t(int ci,int cj){
    for(int i=max(ci-1,1);i<=ci+1&&i<=n;i++){
        for(int j=max(cj-1,1);j<=cj+1&&j<=m;j++){
            if(a[i][j] == '.')a[i][j]='*';
        }
    }
}
int main(){
    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] == 'c'){
                t(i,j);
            }
        }
    }
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i][j] == 'w'){
                if(check(i,j)){
                    f(i,j);
                }
            }
        }
    }
    if(!cnt)cout << "Too cold!";
    return 0;
}

官方答案

#include <bits/stdc++.h>
#define x first
#define y second

using namespace std ;
typedef pair<int,int> PII ;
const int N = 1010 ;
int n , m , u ;
string s[N] ;
int dx[8] = {0 , -1 , -1 , -1 , 0 , 1 , 1 , 1} ;
int dy[8] = {-1 , -1 , 0 , 1 , 1 , 1 , 0 , -1} ;

int main()
{
    cin >> n >> m ;
    for(int i = 1 ; i <= n ; i ++)
    {
        cin >> s[i] ;
        s[i] = " " + s[i] ;
    }
    for(int i = 1 ; i <= n ; i ++)
        for(int j = 1 ; j <= m ; j ++)
            if(s[i][j] == 'w')
            {
                int f = 0 ;
                for(int k = 0 ; k < 8 ; k ++)
                {
                    int fx = i + dx[k] , fy = j + dy[k] ;
                    if(fx >= 1 && fx <= n && fy >= 1 && fy <= m)
                    {
                        if(s[fx][fy] == 'm') f = 1 ;
                    }
                }
                if(!f) s[i][j] = '!' , u ++ ;
            }
    vector<PII> res ;
    for(int i = 1 ; i <= n ; i ++)
        for(int j = 1 ; j <= m ; j ++)
            if(s[i][j] == '.')
            {
                int f = 1 , uc = 0 ;
                for(int k = 0 ; k < 8 ; k ++)
                {
                    int fx = i + dx[k] , fy = j + dy[k] ;
                    if(fx >= 1 && fx <= n && fy >= 1 && fy <= m)
                    {
                        if(s[fx][fy] == '!') uc ++ ;
                        if(s[fx][fy] == 'c' ) f = 0 ;
                    }
                }
                if(uc == u && f && uc) res.push_back({i , j}) ;
            }

    sort(res.begin() , res.end()) ;
    if(res.size())
    {
        for(int i = 0 ; i < res.size() ; i ++)
            cout << res[i].x << " " << res[i].y << "\n" ;
    }
    else cout << "Too cold!" << "\n" ;
    return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值