欢迎光临
我们一直在努力

小红的皇后【牛客tracker & 每日一题】

小红的皇后

时间限制:3 秒 空间限制:256 MB

网页链接

牛客tracker

牛客tracker & 每日一题,完成每日打卡,即可获得牛币。获得相应数量的牛币,能在【牛币兑换中心】,换取相应奖品!助力每日有题做,丰盈牛币日益多!在这里插入图片描述


题目描述

给定一个

n

×

m

n \\times m

n×m 的棋盘,部分格子为障碍物('*'),其余为空格('.')。小红控制一枚皇后,初始位于左上角

(

1

,

1

)

(1, 1)

(1,1),目标是移动到右下角

(

n

,

m

)

(n, m)

(n,m)。皇后一次移动可以选择下列三种方式之一,并沿选定方向前进任意正整数步:

  • 向右:

    (

    x

    ,

    y

    )

    (

    x

    ,

    y

    +

    k

    )

    (x, y) \\to (x, y + k)

    (x,y)(x,y+k)

  • 向下:

    (

    x

    ,

    y

    )

    (

    x

    +

    k

    ,

    y

    )

    (x, y) \\to (x + k, y)

    (x,y)(x+k,y)

  • 向右下:

    (

    x

    ,

    y

    )

    (

    x

    +

    k

    ,

    y

    +

    k

    )

    (x, y) \\to (x + k, y + k)

    (x,y)(x+k,y+k)

其中

k

1

k \\ge 1

k1,并且移动路径上不得出现障碍物。

求皇后从左上角移动到右下角需要的最少步数;若无法到达,输出

1

-1

1


输入描述

第一行输入两个整数

n

,

m

 

(

1

n

,

m

2000

)

n, m\\ (1 \\le n, m \\le 2000)

n,m (1n,m2000)

接下来

n

n

n 行,每行一个长度为

m

m

m 的字符串,字符集为 '.' 与 '*',描述棋盘。保证左上角与右下角均为 '.'。


输出描述

若无法到达,输出 -1;否则输出最少步数。


示例 1

输入:

3 3

.*.
.*.

输出:

-1


示例 2

输入:

3 4
….
**.*
….

输出:

2

解题思路

本题是棋盘上带障碍的皇后最短路问题。皇后每次可以向右、下、右下三个方向移动任意正整数步,且移动路径上不能有障碍。需要求出从左上角到右下角的最少步数,若无法到达则输出 -1。

由于移动方向固定且步数可任意,可以利用动态规划思想,在遍历棋盘时维护三个方向上的最小步数状态,实现线性时间复杂度。

1. 问题等价转化
  • 棋盘大小为 n × m,皇后起始于 (1,1),目标 (n,m)。
  • 三个移动方向分别为:
    • 向右:(x, y + k)
    • 向下:(x + k, y)
    • 向右下:(x + k, y + k) 其中 k ≥ 1,且移动路径上不能经过障碍。
  • 要求最少的移动步数。
2. 动态规划状态设计
  • 定义三个数组:

    • rb[i]:表示从起点到达第 i 行某个格子的最少步数,且该格子可以继续向右移动(即当前行可达的最小步数)。
    • cb[j]:表示从起点到达第 j 列某个格子的最少步数,且可以继续向下移动。
    • db[id]:表示从起点到达某条右下对角线上某个格子的最少步数,且可以继续沿对角线移动。

    对角线索引可通过 id = (i – j) + (m – 1) 唯一映射。

  • 初始时,所有数组值为 INF,起点 (0,0) 步数为 0。

3. 遍历与状态转移

按行从左到右遍历整个棋盘:

  • 遇到障碍 '*': 将当前格所在行、列、对角线的状态全部重置为 INF,因为障碍会阻断该方向的连续移动。

  • 遇到空格 '.': 设当前格子为 (i, j)。 计算到达该格子的最少步数:

    best = min(rb[i], cb[j], db[id])
    cur = (best == INF ? INF : best + 1)

    这里 best 表示从某个方向到达当前格前一步的最小步数,由于需要一次新的移动(转向或首次进入该方向),所以 cur = best + 1。对于起点 (0,0),cur = 0。

    然后用 cur 更新三个状态:

    rb[i] = min(rb[i], cur)
    cb[j] = min(cb[j], cur)
    db[id] = min(db[id], cur)

    这样,后续格子在沿同一方向移动时,可以直接继承较小的步数,而不需要额外加步数。

  • 记录答案:当遍历到右下角 (n-1, m-1) 时,其 cur 即为最少步数。

4. 复杂度分析
  • 时间复杂度:每个格子被访问一次,操作常数次,总复杂度 O(n·m),对于 n, m ≤ 2000 完全可行。
  • 空间复杂度:需要存储棋盘和三个方向数组,O(n·m + n + m + n+m),实际可接受。

总结

利用三个方向状态数组模拟皇后沿固定方向的连续移动特性,通过一次遍历实现动态规划。遇到障碍重置状态,正确维护了“同一方向连续移动步数不增加,改变方向步数加一”的最优性质。最终右下角的状态即为答案。

解题思路

#include <bits/stdc++.h>
using namespace std;

#define endl '\\n'
typedef long long ll;
typedef unsigned long long ull;
typedef vector<vector<ll>> vvt;
typedef pair<ll,ll> pll;
const ll N=1e3+10;
const ll INF=1e9;
const ll M=1e6+10;
const ll mod=1e9+7;

int main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
ll n,m;
cin>>n>>m;
vector<string> g(n);
for(ll i=0;i<n;i++) cin>>g[i];
vector<ll> rb(n, INF);
vector<ll> cb(m, INF);
vector<ll> db(n+m+5, INF);
ll ans=INF;
for(ll i=0;i<n;i++)
{
rb[i]=INF;
for(ll j=0;j<m;j++)
{
ll id=(ij)+(m1);
if(g[i][j]=='*')
{
rb[i]=INF;
cb[j]=INF;
db[id]=INF;
continue;
}
ll cur;
if(i==0&&j==0) cur=0;
else
{
ll best=min(rb[i], min(cb[j], db[id]));
cur=(best>=INF?INF:best+1);
}
if(cur<rb[i]) rb[i]=cur;
if(cur<cb[j]) cb[j]=cur;
if(cur<db[id]) db[id]=cur;
if(i==n1&&j==m1) ans=cur;
}
}
if(ans>=INF) cout<<1<<"\\n";
else cout<<ans<<"\\n";
return 0;
}

赞(0)
未经允许不得转载:171主机测评 » 小红的皇后【牛客tracker & 每日一题】
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址