详解P431 塔防

news2024/9/24 7:18:36

题目

说明

gsy 最近在玩一个塔防游戏,但是这次她控制的是迷宫中的怪兽而非防御塔建造者

游戏的地图是一个 n * m 的矩阵,起点在 (1,1) ,终点在 (n,m) ,gsy 每次可以选择上下左右四个方向移动 1 步

这个地图上有很多的防御塔,gsy 每次移动结束后,所有防御塔都会对它进行一次攻击

在这个游戏中,她离某个防御塔越远,这个防御塔能对她造成的伤害就越高

设 gsy 某次移动到达位置 (x,y) ,某个防御塔位于坐标 (X,Y) ,那么这个防御塔在这一次攻击会对 gsy 造成 |X-x| + |Y-y| 点伤害

为了通关,gsy 又给自己开了金手指,可以使得在这一轮游戏中,防御塔的攻击不会造成伤害,而是造成等值的血量回复

现在 gsy 想找到一条从起点到终点的路径,并且自己在途中受到的来所有自防御塔单次攻击的最小值尽可能大

P.S. 在这个游戏中,gsy 可以走到防御塔的位置上

输入格式

第一行两个数 n,m 。

接下来 n 行,每行 m 个数,如果该数为 0 ,则表示该位置是空地,否则则表示这个位置有防御塔。

数据保证至少存在一个防御塔。

输出格式

一个数表示答案

样例

输入数据 1

3 4

0 1 1 0

0 0 0 0

1 1 1 0

输出数据 1

1

提示

对于 40% 的数据 n,m <= 10

对于 80% 的数据 n,m <= 100

对于 100% 的数据 n,m <= 1000


思路

一开始我是想通过dfs,搜索出一条路径,并将ansmax(ans,这条路径中被攻击的最小值)就行了

但是后来发现dfs肯定超时啊,1000*1000的地图搜路,这不铁超时,后来读题时注意到了一段话:

这不就是再求最小值最大吗?所以由此想到二分。然后考虑二分如何写。

  1. check(mid)的意义是什么?

二分答案这个从(1,1)->(n,m)的路径且满足所有路径上的点里离所有防御塔最近距离最大值check就是判断有没有这样一条路径

  1. 初始时l,r是什么?

l = 0,r = n + m(因为二分的是离所有防御塔最近距离最大值),而地图上2点间最大距离就是n+m,最短距离0

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m,l,r,ans,mid,a[1002][1002],x[10000001],y[10000001],fyt,dx[4] = {-1,0,1,0},dy[4] = {0,1,0,-1},vis[1002][1002];
bool fl;
int f(int x_1,int y_1)//返回这个点离所有防御塔的最近距离
{
  int ans = 0x3f3f3f3f3f;
  for(int i = 1; i <= fyt; i++)
  {
    int jl = abs(x[i] - x_1) + abs(y[i] - y_1);//计算起点到该防御塔的距离
    ans = min(ans,jl);
  }
  return ans;
}
void dfs(int sx,int sy,int p)
{
  if(sx == n && sy == m)
  {
    fl = 1;
    return ;
  }
  vis[sx][sy] = 1;
  for(int i = 0; i < 4; i++)
  {
    int nx = sx + dx[i];
    int ny = sy + dy[i];
    if(nx > 0 && nx <= n && ny > 0 && ny <= m && vis[nx][ny] == 0 && f(nx,ny) >= p && fl == 0) dfs(nx,ny,p);
  }
}
bool check(int x)
{
  fl = 0;
  memset(vis,0,sizeof(vis));
  dfs(1,1,x);
  if(fl == 1)//有这样一条从(1,1)->(n,m)的路径且满足所有路径上的点里离有防御塔的最近距离的最大值>=x
    return 1;
  else return 0;
}
signed main()
{
  scanf("%lld%lld",&n,&m);
  for(int i = 1; i <= n; i++)
    for(int j = 1; j <= m; j++)
    {
      scanf("%lld",&a[i][j]);
      if(a[i][j] == 1)
      {
        x[++fyt] = i;//储存一个防御塔的x,y
        y[fyt] = j;
      }
    }
  r = n + m;//初始化
  while(l <= r)//二分答案
  {
    mid = (l + r) / 2;
    if(check(mid))
    {
      l = mid + 1;
      ans = mid;
    }
    else r = mid - 1;
  }
  cout<<ans;
  return 0;
}

然后该怎么优化呢?可以想到f()函数dfs重复算了很多次,所以应该预处理f()函数的值,并储存在yy[][]中。

那么如何预处理呢?

yy[x][y]是所有防御塔(x,y)最小距离

那路径长度都是一样的

可以来一次多起点的bfs

只不过一开始直接把所有防御塔的坐标扔进queue里就行了

预处理代码:

void bfs()//以多个防御塔为起点bfs整个迷宫来更新yy[][](多起点的bfs)
{
  for(int i = 1; i <= fyt; i++)
  {
    node d = {x[i],y[i]};
    q.push(d);
  }
  while(!q.empty())
  {
    node d = q.front();
    q.pop();
    for(int i = 0; i < 4; i++)
    {
      node t = {d.x + dx[i],d.y + dy[i]};
      if(t.x > 0 && t.x <= n && t.y > 0 && t.y <= m && vis[t.x][t.y] == 0)
      {
        vis[t.x][t.y] = vis[d.x][d.y] + 1;
        yy[t.x][t.y] = min(yy[t.x][t.y],vis[t.x][t.y]);
        q.push(t);
      }
    }
  }

完整代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m,l,r,ans,mid,a[2002][2002],x[10000001],y[10000001],fyt,dx[4] = {-1,0,1,0},dy[4] = {0,1,0,-1},vis[2002][2002],yy[2002][2002];//yy[x][y]是(x,y)这个点离所有防御塔的最近距离
bool fl;
struct node
{
  int x,y;
};
queue<node> q;
void bfs()//以多个防御塔为起点bfs整个迷宫来更新yy[][](多起点的bfs)
{
  for(int i = 1; i <= fyt; i++)
  {
    node d = {x[i],y[i]};
    q.push(d);
  }
  while(!q.empty())
  {
    node d = q.front();
    q.pop();
    for(int i = 0; i < 4; i++)
    {
      node t = {d.x + dx[i],d.y + dy[i]};
      if(t.x > 0 && t.x <= n && t.y > 0 && t.y <= m && vis[t.x][t.y] == 0)
      {
        vis[t.x][t.y] = vis[d.x][d.y] + 1;
        yy[t.x][t.y] = min(yy[t.x][t.y],vis[t.x][t.y]);
        q.push(t);
      }
    }
  }
}
void dfs(int sx,int sy,int p)
{
  if(fl == 1) return ;
  if(sx == n && sy == m)//有一条这样满足条件的路径
  {
    fl = 1;
    return ;
  }
  vis[sx][sy] = 1;
  for(int i = 0; i < 4; i++)
  {
    if(fl == 1) return ;
    int nx = sx + dx[i];
    int ny = sy + dy[i];
    if(nx > 0 && nx <= n && ny > 0 && ny <= m && vis[nx][ny] == 0 && yy[nx][ny] >= p && fl == 0) dfs(nx,ny,p);
    if(fl == 1) return ;
  }
}
bool check(int x)//判断有没有一条从(1,1)->(n,m)的路径且满足所有路径上的点里离有防御塔的最近距离的最大值>=x
{
  fl = 0;
  memset(vis,0,sizeof(vis));
  dfs(1,1,x);
  if(fl == 1)//有这样一条从(1,1)->(n,m)的路径且满足所有路径上的点里离有防御塔的最近距离的最大值>=x
    return 1;
  else return 0;
}
signed main()
{
  scanf("%lld%lld",&n,&m);
  for(int i = 1; i <= n; i++)
    for(int j = 1; j <= m; j++)
    {
      scanf("%lld",&a[i][j]);
      if(a[i][j] == 1)
      {
        x[++fyt] = i;
        y[fyt] = j;
      }
    }
  memset(yy,0x3f,sizeof(yy));
  bfs();
  r = n + m;
  while(l <= r)
  {
    mid = (l + r) / 2;
    if(check(mid))
    {
      l = mid + 1;
      ans = mid;
    }
    else r = mid - 1;
  }
  cout<<ans;
  return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/176405.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

“华为杯”研究生数学建模竞赛2005年-【华为杯】B题:空中加油问题的讨论(附获奖论文及C++代码)

赛题描述 对飞行中的飞机进行空中加油,可以大大提高飞机的直航能力。为了简化问题,便于讨论,我们作如下假设。 少辅机架数两种情况给出你的作战方案。 论文 一. 问题重述 空中加油技术可以大大提高飞机的直航能力。作战飞机称为主机,加油机称 为辅机。已知:( 1 )主…

[创业之路-50] :动态股权机制 -5- 创业公司股权分配常见的坑

1、 分工不清晰&#xff0c;决策不清晰&#xff0c;理念不一致分工必须要简单明晰初创公司的合伙人一般是三到五个&#xff0c;最合理的架构一开始最好是三个人&#xff0c;相互之间需要一段时间的磨合&#xff0c;了解清楚各自的特长&#xff0c;工作经历等等&#xff0c;不要…

微信小程序开发uni-app

一、uni-app简介官网&#xff1a;https://uniapp.dcloud.io/PC端&#xff1b;移动端&#xff1a;&#xff08;APP&#xff0c;WebApp&#xff09;&#xff1b;纯原生&#xff1a;&#xff08;IOS,Android &#xff09; 应用商店&#xff1b;H5Hybrid 模式&#xff08;混合&…

活动星投票最美农商人网络评选微信的投票方式线上免费投票

“最美农商人”网络评选投票_视频投票的相关评选_投票统计_微信不记名免费评选投票用户在使用微信投票的时候&#xff0c;需要功能齐全&#xff0c;又快捷方便的投票小程序。而“活动星投票”这款软件使用非常的方便&#xff0c;用户可以随时使用手机微信小程序获得线上投票服务…

树莓派Python虚拟环境、PyQt5、PySide2

要从头设置好一台可用于开发的树莓派&#xff0c;可以参考树莓派 4B 无屏幕&#xff0c;连接WiFi、SSH、VNC&#xff0c;系统换源、pip换源&#xff0c;安装中文输入法 Python虚拟环境 树莓派&#xff08;或者说arm平台&#xff09;使用Python虚拟环境的正确方式是使用pipenv…

【MyBatis】| 使⽤javassist⽣成类、面向接口的方式进行CRUD

目录 一&#xff1a;使⽤javassist⽣成类 1. Javassist的使⽤ 2. 动态生成类并实现接口 3. MyBatis中接⼝代理机制及使⽤ 二&#xff1a;面向接口的方式进行CRUD 一&#xff1a;使⽤javassist⽣成类 Javassist是⼀个开源的分析、编辑和创建Java字节码的类库。是由东京⼯业⼤…

SSH原理与运用

SSH原理与运用 SSH原理与运用&#xff08;一&#xff09;&#xff1a;远程登录 SSH原理与运用&#xff08;二&#xff09;&#xff1a;远程操作与端口转发 一. 什么是SSH&#xff1f; 简单说&#xff0c;SSH是一种网络协议&#xff0c;用于计算机之间的加密登录。需要指出的…

7个流行的强化学习算法及代码实现

目前流行的强化学习算法包括 Q-learning、SARSA、DDPG、A2C、PPO、DQN 和 TRPO。 这些算法已被用于在游戏、机器人和决策制定等各种应用中&#xff0c;并且这些流行的算法还在不断发展和改进&#xff0c;本文我们将对其做一个简单的介绍。 1、Q-learning Q-learning&#xff1…

23种设计模式(十九)——迭代器模式【数据结构】

文章目录 意图什么时候使用迭代器真实世界类比迭代器模式的实现迭代器模式的优缺点亦称:Iterator 意图 提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。 什么时候使用迭代器 1、当集合背后为复杂的数据结构, 且你希望对客户端隐藏其复杂性时 …

[QMT]05-获取基础行情信息

函数&#xff1a;获取合约基础信息get_instrument_detail(stock_code)1释义获取合约基础信息参数stock_code - string 合约代码返回 dict 数据字典&#xff0c;{ field1 : value1, field2 : value2, ... }&#xff0c;找不到指定合约时返回NoneExchangeID - string 合约市场代码…

零基础学JavaWeb开发(二十)之 spring框架(3)

SpringBean的AOP 1、AOP基本的概念 AOP(Aspect Oriented Programming)是一种面向切面的编程思想。面向切面编程是将程序抽象成各个切面&#xff0c;即解剖对象的内部&#xff0c;将那些影响了多个类的公共行为抽取到一个可重用模块里&#xff0c;减少系统的重复代码&#xff…

二叉树知识锦囊(三)

作者&#xff1a;爱塔居 专栏&#xff1a;数据结构​​​​​​ 作者简介&#xff1a;大三学生&#xff0c;希望和大家一起进步&#xff01; 目录 前言 1. 检查两棵树是否相同。 2. 另一颗树的子树。 3. 翻转二叉树。 4. 判断一颗二叉树是否是平衡二叉树。 5. 对称二叉树。 前…

【Python】Python数据结构之布尔类型(bool)

目录&#xff1a;Python数据结构之布尔类型&#xff08;bool&#xff09;一、布尔说明二、判定三、布尔运算&#xff1a; and, or, not一、布尔说明 Python 中布尔值使用常量True 和 False来表示&#xff1b;注意大小写。比较运算符< > 等返回的类型就是bool类型&#…

C++虚继承,虚基表 ,菱形继承以及解决方法

目录菱形继承形成原因出现二义性变量的内存布局应对方案虚继承 vitrual解决二义性变量内存布局--虚基表感悟关于代码复用等的另一种关系-组合菱形继承形成原因 多继承&#xff0c;呈菱形状 菱形继承代码: class A { public:A() {}int _a ; }; class B :public A { public…

分享131个ASP源码,总有一款适合您

ASP源码 分享131个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 131个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/17vXlBvqeYPM5-XUlu5zaAg?pwd3zzi 提取码&#x…

【Qt】如何使用QtCreator向工程添加文件

文章目录一、导读二、盘一盘文件模板&#xff08;2-1&#xff09;添加C/C文件&#xff08;2-2&#xff09;添加Modeling文件&#xff08;2-3&#xff09;添加Qt相关文件&#xff08;2-4&#xff09;添加GLSL相关文件&#xff08;2-5&#xff09;添加其他文件三、总结一、导读 …

【JavaSE专栏3】JDK安装、IntelliJ IDEA安装、配置环境变量

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发&#xff08;Vue、SpringBoot和微信小程序&#xff09;、系统定制、远程技术指导。CSDN学院、蓝桥云…

【苹果相册推】Xcode项目,我们将其命名为mypushchat,以及调试的iOS设备

推荐内容IMESSGAE相关 作者✈️IMEAX推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容3.日历推 *** …

第二个程序——客户端ClientUI

简介 在我的上一篇文章中&#xff0c;我已经介绍了如何实现“在线聊天室”中的服务器端ServerUI&#xff0c;服务器端作为整个聊天系统的“中继系统”&#xff0c;负责转发用户的信息到聊天室&#xff0c;可以转发给聊天室中的每一个人&#xff08;即&#xff0c;群聊&#xf…

一期Go群问答-并发控制-数据竞争-错误与异常

每周更新Go技术交流群的群问答内容&#xff0c;有需要可发我Go加群讨论学习。 并发控制 waitGroup.done()不是必须写在main方法中吗? 为什么我的协程没有成功等待&#xff1f; 熊&#xff1a;如果用了wait group&#xff0c;请求就直接卡住了&#xff0c;如果只有一个gorou…