首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >二维网格上最大可达面积的动态规划问题

二维网格上最大可达面积的动态规划问题
EN

Stack Overflow用户
提问于 2020-10-06 02:28:58
回答 5查看 938关注 0票数 2

我最近遇到了这个动态编程问题,我想看看是否有人对解决这个问题的方法有想法。我在这方面遇到了困难,这可能是因为我被困在了创建一棵大树来处理所有可能性的想法中。

问题

有一个字符可以在二维(x,y)坐标网格上移动.字符放置在点(0,0)。 从(x,y)字符可以移动到(x+1,y),(x-1,y),(x,y+1)和(x,y-1)。 有些地点是危险的,埋有地雷。为了知道哪些点是安全的,我们检查abs(x)和abs(y)的数字之和是否小于或等于23。 例如,点(64,-59)不安全,因为6+4+5+9= 24,大于23。点(105,-17)是安全的,因为1

  • 0+5+1+7= 14,小于23。

字符可以访问的区域有多大?

EN

回答 5

Stack Overflow用户

发布于 2020-10-06 03:24:01

对于-1000, -1000 ... 1000, 1000字段max有相同的假设,下面是用C#编写的简单BFS版本

函数来检查点是否安全。

代码语言:javascript
运行
复制
bool isSafe(int x, int y){
    return (sum(Math.Abs(x)) + sum(Math.Abs(y))) < 24;
}

数字之和(假设非负输入)

代码语言:javascript
运行
复制
int sum(int n){
    int ret = 0;        
    while(n > 0){
        ret += n%10;
        n = n/10;
    }
    return ret;
}

BFS算法

代码语言:javascript
运行
复制
var visited = new bool[2000, 2000];
var queue = new Queue<(int x, int y)>();

var steps = new List<(int di, int dj)>() {(-1, 0), (1, 0), (0, -1), (0, 1)};

int count = 1; 

queue.Enqueue((0, 0));
visited[1000, 1000] = true;

while (queue.Count != 0)
{
    var point = queue.Dequeue();
    foreach (var step in steps)
        if (!visited[point.x + step.di + 1000, point.y + step.dj + 1000] && isSafe(point.x + step.di, point.y + step.dj))
        {
            count++;
            visited[point.x + step.di + 1000, point.y + step.dj + 1000] = true;
            queue.Enqueue((point.x + step.di, point.y + step.dj));
        }
}

Console.WriteLine(count);   

输出

代码语言:javascript
运行
复制
592597

在发现可达的单元格后,您可以看到图

票数 2
EN

Stack Overflow用户

发布于 2020-10-06 02:52:32

让我们编写一个简单的DFS

首先,让我们考虑可以访问多少个单元,这样我们的算法就不会永远运行下去。在(999,999)的左上角和(-999,999)的右下角,你不能走得更远,因为正方形的一个坐标是±999,但是9+9+9> 23。在这个广场上有1999年*< 4M点,所以DFS会非常快。

代码语言:javascript
运行
复制
#include <cmath>
#include <iostream>

const int SQUARE_SIDE = 1'000;

// v[i][j] is true if cell (i - SQUARE-SIDE, j - SQUARE_SIDE) was already
// visited during DFS, false otherwise.
bool v[2 * SQUARE_SIDE][2 * SQUARE_SIDE];
int answer = 0;

const struct {
  int dx;
  int dy;
} moves[] = {
    {1, 0},   // Up
    {-1, 0},  // Down
    {0, -1},  // Left
    {0, 1}    // Right
};

int calc_abs_sum(int n) {
  n = abs(n);
  int sum = 0;
  while (n) {
    sum += n % 10;
    n /= 10;
  }
  return sum;
}

void dfs(int x, int y) {
  // Add SQUARE_SIDE to make indices non-negative.
  v[x + SQUARE_SIDE][y + SQUARE_SIDE] = true;
  answer++;

  for (const auto &move : moves)
    if (calc_abs_sum(x + move.dx) + calc_abs_sum(y + move.dy) <= 23 &&
        !v[x + move.dx + SQUARE_SIDE][y + move.dy + SQUARE_SIDE]) {
      dfs(x + move.dx, y + move.dy);
    }
}

int main() {
  dfs(0, 0);
  std::cout << answer << std::endl;
}

我们就有592597了。

票数 1
EN

Stack Overflow用户

发布于 2020-10-14 00:51:04

我的回答太长了,所以我在HackerNoon的一篇文章中记录了一个Java解决方案,以及思考过程和对坐标系统的详细解释。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64218531

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档