【题解】射击-C++
Description
不难发现,豆豆能从很多事情中去思考数学,于是豆豆父母决定让他去练习射击,这是项需要集中注意力的运动,相信
能够让豆豆暂时脱离数学。学习射击的第一天就让豆豆产生 了浓厚的兴趣,射击的靶子是大饼圆,射击枪的子弹近
似圆柱,为什么要圆的不能是其他的 形状呢,于是豆豆开始构思,设计了这样一个好玩的问题:N*M 的方形格子靶子,
每个格子有两种状态凸或者凹(如下图浅色表示凹,深色表示凸)

现在用一个十字横截面的子弹(填充黑色部分)去射击,被射中的小格子凹变凸,凸变 凹,子弹放大后的横截面如下图

这种子弹最多可以覆盖 5 个格子,如图打完后,5 个格子凹凸状态发生了变化

请问最少需要几次射击使靶子中所有小格子都呈现凹的状态。
注意:子弹中心点如果打到四个角上则只会影响 3 个格子,如下图黑色格子表示被子 弹中心点正好击中左上角后覆
盖的 3 个格子,如果打到除四个角的边界上,则会影响到 4 个格子,如下图右侧的 4 个黑色格子所示,这是子弹中
心点打中第 3 行第 6 列时的覆盖情 况。(也就是说子弹超出靶子部分不起效)

Input
第一行两个用空格隔开的数字 N 和 M(1<=N,M<=17)
接下来 N 行 述靶子中小格子的状态,‘X’表示凸,‘.’表示凹。
Output
输出所需要的最少射击次数
注意:输入数据保证有解
Sample Input
【样例输入 1】
5 5
XX.XX
X.X.X
.XXX.
X.X.X
XX.XX
【样例输入 2】
8 9
…XXXXX…
.X…X.
X…X.X…X
X…X
X.X…X.X
X…XXX…X
.X…X.
…XXXXX…
Sample Output
【样例输出 1】
5
【样例输出 2】
25
这道题目还是一道dfs的问题,基本上是这道题目的改版,但是在数据范围上改变了许多,如果用上一道题的方法的话连5*5的图都不能过,都需要8s多。
怎么优化呢?
我们可以不一味的列举每一个位置翻还是不翻,这样做的时间复杂度最高能达到O(n^n),很明显,到了n≤17的范围下,这种方法肯定会炸。
为什么不通过几个简单的枚举+条件分支判断翻哪个位置呢?这样的话,就算最坏的情况,也不会耗费O(n^n)的时间复杂度。
首先,在翻棋子的基础上,写出shoot函数(也就是射击这一个位置)
void shoot(int x,int y)
{
b[x][y]=!b[x][y];
b[x-1][y]=!b[x-1][y];
b[x+1][y]=!b[x+1][y];
b[x][y-1]=!b[x][y-1];
b[x][y+1]=!b[x][y+1];
sum++;
}
输入的时候最好把原图转换成01矩阵,后面在dfs中直接使用双重for把01矩阵复制一份【滑稽】。
依然是dfs模板贴一下:
void dfs()//参数用来表示状态
{
if(到达终点状态)
{
...//根据题意添加
return;
}
if(越界或者是不合法状态)
return;
if(特殊状态)//剪枝
return ;
for(扩展方式)
{
if(扩展方式所达到状态合法)
{
修改操作;//根据题意来添加
标记;
dfs();
(还原标记);
//是否还原标记根据题意
//如果加上(还原标记)就是 回溯法
}
}
}
因为这道题目的如果到达目标状态要做的事情有点多,先讲拓展。
拓展无非就是两种情况,射或者不射,如果射了,就要注意还原标记。
这部分就四行
ok[dep]=0;
dfs(dep+1);
ok[dep]=1;
//↑选↓不选
dfs(dep+1);
关键是前面、
当深度dep到了m+1(到达边界)的时候要考虑的东西有点多:
if(dep==m+1)
{
sum=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
b[i][j]=mp[i][j];
}
}
//复制原图
for(int i=1;i<=m;i++)
{
if(ok[i]==1)
{
shoot(1,i);
}
}
for(int i=2;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(b[i-1][j]==1)
{
shoot(i,j);
}
}
}
f=1;
for(int i=1;i<=m;i++)
{
if(b[n][i]==1)
{
f=0;
}
}
if(f&&sum<ans)
{
ans=sum;
}
return;
}
自行理解(强制)
完整代码:
#include<bits/stdc++.h>
using namespace std;
char mp1[29][29];//原图
int n,m,ans=0x7f7f7f7f,sum;
int ok[29],b[29][29]/*每次dfs用来复制mp*/,mp[29][29];//01矩阵;
void shoot(int x,int y)
{
b[x][y]=!b[x][y];
b[x-1][y]=!b[x-1][y];
b[x+1][y]=!b[x+1][y];
b[x][y-1]=!b[x][y-1];
b[x][y+1]=!b[x][y+1];
sum++;
}
void dfs(int dep)
{
int f;
if(dep==m+1)
{
sum=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
b[i][j]=mp[i][j];
}
}
//复制原图
for(int i=1;i<=m;i++)
{
if(ok[i]==1)
{
shoot(1,i);
}
}
for(int i=2;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(b[i-1][j]==1)
{
shoot(i,j);
}
}
}
f=1;
for(int i=1;i<=m;i++)
{
if(b[n][i]==1)
{
f=0;
}
}
if(f&&sum<ans)
{
ans=sum;
}
return;
}
ok[dep]=0;
dfs(dep+1);
ok[dep]=1;
//↑选↓不选
dfs(dep+1);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>mp1[i][j];
if(mp1[i][j]=='X')
mp[i][j]=1;
else
mp[i][j]=0;
}
}
dfs(1);
cout<<ans<<endl;
return 0;
}
ov.
【题解】射击-C++的更多相关文章
- 射击比赛 (POJ 1719) 题解
[问题描述] 我们假设射击的目标是一个由R*C(2≤R≤C≤ 1000)个小方格组成的矩形网格.网格中每一列恰有2个白色的小方格和R-2个黑色的小方格.定义网格的行从顶至底编号为1~R,列从左至右编号 ...
- bzoj usaco 金组水题题解(1)
UPD:我真不是想骗访问量TAT..一开始没注意总长度写着写着网页崩了王仓(其实中午的时候就时常开始卡了= =)....损失了2h(幸好长一点的都单独开了一篇)....吓得赶紧分成两坨....TAT. ...
- 【LOJ#2402】[THUPC2017]天天爱射击(整体二分)
[LOJ#2402][THUPC2017]天天爱射击(整体二分) 题面 LOJ 题解 显然对于每块木板可以二分被打烂的时间. 那么直接上整体二分处理就行了. #include<iostream& ...
- JZOJ 3928. 【NOIP2014模拟11.6】射击
3928. [NOIP2014模拟11.6]射击 (Standard IO) Time Limits: 1000 ms Memory Limits: 65536 KB Description 有问题, ...
- 题解-NOI2003 智破连环阵
题面 NOI2003 智破连环阵 有 \(m\) 个靶子 \((ax_j,ay_j)\) 和 \(n\) 个箭塔 \((bx_i,by_i)\).每个箭塔可以射中距离在 \(k\) 以内的靶子.第 \ ...
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
随机推荐
- UWP入门(五)--控件模板
原文:UWP入门(五)--控件模板 通过在 XAML 框架中创建控件模板,你可以自定义控件的可视结构和可视行为(eg:勾选框的三种状态). 控件有多个属性,如 Background.Foregroun ...
- 如何在 Linux 中添加一块大于 2TB 的新磁盘?
你有没有试过使用 fdisk 对大于 2TB 的硬盘进行分区,并且纳闷为什么会得到需要使用 GPT 的警告? 是的,你看到的没错.我们无法使用 fdisk 对大于 2TB 的硬盘进行分区. 在这种情况 ...
- SimpleDateFormat之后为何多了一年,难道Java API也这么不靠谱?
这一切的背后到底是机器故障,还是程序的bug? 难道Java API也不靠谱 朋友在我博客上发现一时间明显错误,操作时间怎么会是2016年?在同一个for循环输出到页面的时间,唯独这一个时间不对,整整 ...
- Qt Creator调用VS2008生成的DLL注意事项 good
问题:生成的dll文件QT无法静态/隐式调用 分析:调用的lib库可能是msvc编译的,而我用Qt调用,Qt默认编译器是minGW,两种编译器生成的函数名不一样,所以调用的时候你要用哪个函数,编译结果 ...
- 一条命令,秒秒钟完成MD5、SHA1校验,这就叫效率!
相信很多奋斗在运维战线的小伙伴们经常会遇到版本升级之类的问题.笔者之前所在的公司每次进行版本发布的时候都会附带MD5校验哈希值,每次升级之前一般都要核对MD5哈希值的,刚刚开始的时候对Linux并不是 ...
- 关于案例中核心dao的解释
很多小伙伴不太理解核心dao,说这是干什么的,接下来我将一一为大家解答: 1.说到核心dao不得不说到单表操作,单表操作顾名思义是对单张数据库表的CRUD操作,实际情况中我们追求将表与表的关系映射到对 ...
- 【数据结构】30、hashmap=》hash 计算方式
前提知识 写在前面,为什么num&(length - 1) 在length是2的n次幂的时候等价于num%length n - 1意味着比n最高位小的位都为1,而高的位都为0,因此通过与可以剔 ...
- ZooKeeper学习之路(一)—— ZooKeeper简介及核心概念
一.Zookeeper简介 Zookeeper是一个开源的分布式协调服务,目前由Apache进行维护.Zookeeper可以用于实现分布式系统中常见的发布/订阅.负载均衡.命令服务.分布式协调/通知. ...
- jQuery入门——注册事件
下面举例介绍注册事件的几种方法: 以光棒效果为例 1.bind注册: <!DOCTYPE html> <html> <head> <meta charset= ...
- PATA 1011 World Cup Betting (20)
1011. World Cup Betting (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Wit ...