2023-03-11:给定一个N*M的二维矩阵,只由字符‘O‘‘X‘‘S‘‘E‘组成, ‘O‘表示这个地方是可通行的平地, ‘X‘表示这个地方是不可通行的障碍, ‘S‘表示这个地方有一个士兵,全

Posted 福大大架构师每日一题

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2023-03-11:给定一个N*M的二维矩阵,只由字符‘O‘‘X‘‘S‘‘E‘组成, ‘O‘表示这个地方是可通行的平地, ‘X‘表示这个地方是不可通行的障碍, ‘S‘表示这个地方有一个士兵,全相关的知识,希望对你有一定的参考价值。

2023-03-11:给定一个N*M的二维矩阵,只由字符’O’、‘X’、‘S’、'E’组成,
'O’表示这个地方是可通行的平地,
'X’表示这个地方是不可通行的障碍,
'S’表示这个地方有一个士兵,全图保证只有一个士兵,
'E’表示这个地方有一个敌人,全图保证只有一个敌人,
士兵可以在上、下、左、右四个方向上移动,
走到相邻的可通行的平地上,走一步耗费a个时间单位,
士兵从初始地点行动时,不管去哪个方向,都不用耗费转向的代价,
但是士兵在行动途中,如果需要转向,需要额外再付出b个时间单位。
返回士兵找到敌人的最少时间。
如果因为障碍怎么都找不到敌人,返回-1,
1 <= N,M <= 1000,
1 <= a,b <= 100000,
只会有一个士兵、一个敌人。
来自华为。

答案2023-03-11:

Dijkstra算法+优先级队列。

代码根据山寨版chatgpt稍做修改写的。这不得不承认chatgpt很强大,这还是山寨版的,感觉比我自己写得还要好。

以下代码是生成的rust代码,稍微做了修改。如下:

use rand::Rng;
use std::cmp::Reverse;
use std::collections::BinaryHeap;
fn random_map(n: usize, m: usize) -> Vec<Vec<char>> 
    let mut map = vec![vec!['O'; m]; n];
    for i in 0..n 
        for j in 0..m 
            if rand::thread_rng().gen_range(0, 2) == 0 
                map[i][j] = 'X';
            
        
    
    let si = rand::thread_rng().gen_range(0, n);
    let sj = rand::thread_rng().gen_range(0, m);
    map[si][sj] = 'S';
    let (mut ei, mut ej) = (si, sj);
    while ei == si && ej == sj 
        ei = rand::thread_rng().gen_range(0, n);
        ej = rand::thread_rng().gen_range(0, m);
    
    map[ei][ej] = 'E';
    map


fn main() 
    let n = 3;
    let m = 4;
    let v = 10;
    println!("功能测试开始");
    for _ in 0..2000 
        let map = random_map(n, m);
        let a = rand::thread_rng().gen_range(1, v + 1);
        let b = rand::thread_rng().gen_range(1, v + 1);
        let ans1 = min_cost1(&map, a, b);
        let ans2 = min_cost2(&map, a, b);
        if ans1 != ans2 
            println!("出错了");
            println!("", ans1);
            println!("", ans2);
            return;
        
    
    println!("功能测试结束");

    println!("性能测试开始");
    let n = 1000;
    let m = 1000;
    let v = 100000;
    let a = rand::thread_rng().gen_range(1, v + 1);
    let b = rand::thread_rng().gen_range(1, v + 1);
    let map = random_map(n, m);
    println!("数据规模 :  * ", n, m);
    println!("通行代价 : ", a);
    println!("转向代价 : ", b);
    let start = std::time::Instant::now();
    min_cost2(&map, a, b);
    let end = std::time::Instant::now();
    println!("运行时间 : 毫秒", (end - start).as_millis());
    println!("功能测试结束");


fn min_cost1(map: &[Vec<char>], a: i32, b: i32) -> i32 
    let n = map.len();
    let m = map[0].len();
    let mut start_x = 0;
    let mut start_y = 0;
    for i in 0..n 
        for j in 0..m 
            if map[i][j] == 'S' 
                start_x = i;
                start_y = j;
            
        
    
    let mut visited = vec![vec![vec![false; 4]; m]; n];
    let p1 = f(&map, start_x, start_y, 0, a, b, &mut visited);
    let p2 = f(&map, start_x, start_y, 1, a, b, &mut visited);
    let p3 = f(&map, start_x, start_y, 2, a, b, &mut visited);
    let p4 = f(&map, start_x, start_y, 3, a, b, &mut visited);
    let ans = p1.min(p2).min(p3).min(p4);
    if ans == i32::MAX 
        -1
     else 
        ans - a
    


fn f(
    map: &[Vec<char>],
    si: usize,
    sj: usize,
    d: usize,
    a: i32,
    b: i32,
    visited: &mut Vec<Vec<Vec<bool>>>,
) -> i32 
    let n = map.len();
    let m = map[0].len();
    if si >= n || sj >= m || map[si][sj] == 'X' || visited[si][sj][d] 
        return i32::MAX;
    
    if map[si][sj] == 'E' 
        return a;
    
    visited[si][sj][d] = true;
    let p0 = f(&map, si.checked_sub(1).unwrap_or(0), sj, 0, a, b, visited);
    let p1 = f(&map, si + 1, sj, 1, a, b, visited);
    let p2 = f(&map, si, sj.checked_sub(1).unwrap_or(0), 2, a, b, visited);
    let p3 = f(&map, si, sj + 1, 3, a, b, visited);
    let p0 = if d != 0 && p0 != i32::MAX  p0 + b  else  p0 ;
    let p1 = if d != 1 && p1 != i32::MAX  p1 + b  else  p1 ;
    let p2 = if d != 2 && p2 != i32::MAX  p2 + b  else  p2 ;
    let p3 = if d != 3 && p3 != i32::MAX  p3 + b  else  p3 ;
    let ans = p0.min(p1).min(p2).min(p3);
    visited[si][sj][d] = false;
    if ans == i32::MAX 
        ans
     else 
        ans + a
    


fn min_cost2(map: &[Vec<char>], a: i32, b: i32) -> i32 
    let n = map.len();
    let m = map[0].len();
    let mut start_x = 0;
    let mut start_y = 0;
    for i in 0..n 
        for j in 0..m 
            if map[i][j] == 'S' 
                start_x = i;
                start_y = j;
            
        
    
    let mut heap = BinaryHeap::new();
    heap.push((Reverse(0), start_x, start_y, 0));
    heap.push((Reverse(0), start_x, start_y, 1));
    heap.push((Reverse(0), start_x, start_y, 2));
    heap.push((Reverse(0), start_x, start_y, 3));
    // (i,j,朝向)
    let mut visited = vec![vec![vec![false; 4]; m]; n];
    let mut ans = -1;
    while let Some((Reverse(cost), x, y, direction)) = heap.pop() 
        if visited[x][y][direction] 
            continue;
        
        if map[x][y] == 'E' 
            ans = cost;
            break;
        
        visited[x][y][direction] = true;
        add(
            x as i32 - 1,
            y as i32,
            0,
            direction,
            cost,
            a,
            b,
            map,
            &mut visited,
            &mut heap,
        );
        add(
            x as i32 + 1,
            y as i32,
            1,
            direction,
            cost,
            a,
            b,
            map,
            &mut visited,
            &mut heap,
        );
        add(
            x as i32,
            y as i32 - 1,
            2,
            direction,
            cost,
            a,
            b,
            map,
            &mut visited,
            &mut heap,
        );
        add(
            x as i32,
            y as i32 + 1,
            3,
            direction,
            cost,
            a,
            b,
            map,
            &mut visited,
            &mut heap,
        );
    
    ans


// 从(x,y, pre_d) -> (i,j,d)
// 走格子的代价a
// 转向的代价是b
// pre_c + a
fn add(
    i: i32,
    j: i32,
    direction: usize,
    pre_direction: usize,
    pre_cost: i32,
    a: i32,
    b: i32,
    map: &[Vec<char>],
    visited: &mut Vec<Vec<Vec<bool>>>,
    heap: &mut BinaryHeap<(Reverse<i32>, usize, usize, usize)>,
) 
    let n = map.len() as i32;
    let m = map[0].len() as i32;
    if i < 0
        || i >= n
        || j < 0
        || j >= m
        || map[i as usize][j as usize] == 'X'
        || visited[i as usize][j as usize][direction]
    
        return;
    
    let mut cost = pre_cost + a;
    if direction != pre_direction 
        cost += b;
    
    heap.push((Reverse(cost), i as usize, j as usize, direction));



以下代码是生成的golang代码,稍微做了修改。如下:

package main

import (
	"container/heap"
	"fmt"
	"math/rand"
	"time"
)

func minCost1(mapData [][]byte, a int, b int) int 
	// 获取地图大小和起点位置
	n, m := len(mapData), len(mapData[0])
	startX, startY := 0, 0
	for i := 0; i < n; i++ 
		for j := 0; j < m; j++ 
			if mapData[i][j] == 'S' 
				startX, startY = i, j
				break
			
		
	

	// 初始化 visited 数组
	visited := make([][][]bool, n)
	for i := range visited 
		visited[i] = make([][]bool, m)
		for j := range visited[i] 
			visited[i][j] = make([]bool, 4)
		
	

	// 计算从四个方向到达终点的最短距离
	p1 := 二维数组---矩阵相关问题

二维数组---矩阵相关问题

二维数组---矩阵相关问题

最大子矩阵

矩阵的旋转

bzoj2351[BeiJing2011]Matrix 二维Hash