算法 每日一题——2022、6、24

题目:立方体IV

题目描述:

Vincenzo 决定制作立方体 IV,但所有预算只够制作一个正方形迷宫。

它是一个完美的迷宫,每个房间都呈正方形,并具有 44 扇门(四个边一边 11 个)。

每个房间里都有一个号码。

一个人只有在下一个房间的号码比当前房间的号码大 11 的情况下,才能从当前房间移动到下一个房间。

现在,Vincenzo 为所有房间分配了唯一的号码(1,2,3,…S21,2,3,…S2)然后将 S2S2 个人放在了迷宫中,每个房间 11 个,其中 SS 是迷宫的边长。

能够移动次数最多的人将获胜。

弄清楚谁将成为赢家,以及他将能够到达的房间数量。

输入格式

第一行包含整数 TT,表示共有 TT 组测试数据。

每组测试数据第一行包含整数 SS,表示迷宫的边长。

接下来 SS 行,每行包含 SS 个整数,表示具体的迷宫的房间号分布,需注意 1,2,3,…S21,2,3,…S2 这 S2S2 个数字,每个数字只出现一次。

输出格式

每组数据输出一个结果,每个结果占一行。

结果表示为 Case #x: r d,其中 xx 是组别编号(从 11 开始),rr 是获胜的人最初所在房间的房间号,dd 是他可以到达的房间数量。

如果有多个人可到达的房间数相同,那么最初所在房间的房间号最小的人将获胜。

数据范围

1≤T≤1001≤T≤100,
1≤S≤10001≤S≤1000

输入样例:

2
2
3 4
1 2 


3
1 2 9 
5 3 8 
4 6 7 

输出样例:

Case #1: 1 2
Case #2: 6 4

 分析:

由于题目中的要求为只能进入比当前房间号码大1的房间,所以对于当前房间进行遍历四个方向查找是否有满足条件的即可

基本算法思想:

对矩阵中的房间从低号到高依次遍历,每一轮结束进行比较,最后输出该组数据的结构

算法优化:

设我们从一号房间开始查找,假设从1号房间一直能走到第n号房间。那么从2号房间开始也只能走到第n号房间,即此轮可以中最大的应该是从1号房间开始,可以走n个房间,从而可以直接省略从2号、3号......n号房间开始时检索的情况。所以下一次的检索应该从第n+1号房间开始检索可以走多少个房间。

时间复杂度
因为每个房间最多遍历 1 次,所以这个算法的时间复杂度就是 O(n2)

空间复杂度
我们需要记录每个房间的信息,而房间数是 O(n2),所以这个算法的空间复杂度也是 O(n2)。

代码:

#include <iostream>
using namespace std;
typedef struct Tag{
    int x;
    int y;
}Tag;
const int N = 1001;
int T,S;
int g[N][N];//迷宫
Tag tag[N * N];//房间队列
int dx[4] = {-1,0,1,0};//x偏移量
int dy[4] = {0,1,0,-1};//y偏移量


int main() {
    cin>> T;
    for(int t = 0; t < T; t++){//t:组别号,即有多少组需要分析的数据
        cin>> S;
        for(int i = 0; i < S; i++){
            for(int j = 0; j < S; j++){
                cin>> g[i][j];
                tag[g[i][j]] = {i,j};//数据读入迷宫,构建迷宫
            }
        }
        int i = 1, max = 0, id ;//max:能够走的房间最大数 id:起始房间号
        for(;i <= S * S;){
            int temp = i;//记录好开始的房间号,后面i会修改
            while (i <= S * S){
                bool flag = false;
                int idx = tag[i].x,idy = tag[i].y;
                for(int d =0; d < 4; d++){
                    int a = idx + dx[d];
                    int b = idy + dy[d];
                    if(a < 0 || a >= S || b < 0 || b >= S){//判断是否越界
                        continue;
                    }
                    if(g[a][b] == g[idx][idy]+1){//满足条件后置为true,break查看下一房间是否还能继续走
                        flag = true;
                        break;
                    }
                }
                i++;//控制for语句执行后的条件,i即为下一轮检索的开始房间号
                if (!flag){//flag为false即当前轮已经检索到最佳情况的房间号,无法继续到下一房间
                    break;
                }
            }
            if(max < i - temp){//i-temp : 当前轮次能够走的房间最大数,和之前轮次进行比较更新
                max = i - temp;
                id = temp;
            }

        }
        cout<< "Case #" << t+1 << ": " << id << " " << max << endl;
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值