入门OJ 3204【射击】
描述
不难发现,豆豆能从很多事情中去思考数学,于是豆豆父母决定让他去练习射击,这是项需要集中注意力的运动,相信
能够让豆豆暂时脱离数学。学习射击的第一天就让豆豆产生 了浓厚的兴趣,射击的靶子是大饼圆,射击枪的子弹近
似圆柱,为什么要圆的不能是其他的 形状呢,于是豆豆开始构思,设计了这样一个好玩的问题:N*M 的方形格子靶子,
每个格子有两种状态凸或者凹(如下图浅色表示凹,深色表示凸)
现在用一个十字横截面的子弹(填充黑色部分)去射击,被射中的小格子凹变凸,凸变 凹,子弹放大后的横截面如下图
这种子弹最多可以覆盖 5 个格子,如图打完后,5 个格子凹凸状态发生了变化
请问最少需要几次射击使靶子中所有小格子都呈现凹的状态。
注意:子弹中心点如果打到四个角上则只会影响 3 个格子,如下图黑色格子表示被子 弹中心点正好击中左上角后覆
盖的 3 个格子,如果打到除四个角的边界上,则会影响到 4 个格子,如下图右侧的 4 个黑色格子所示,这是子弹中
心点打中第 3 行第 6 列时的覆盖情 况。(也就是说子弹超出靶子部分不起效)
输入输出格式
输入
第一行两个用空格隔开的数字 N 和 M(1<=N,M<=17)
接下来 N 行 述靶子中小格子的状态,‘X’表示凸,‘.’表示凹。
输出
输出所需要的最少射击次数
注意:输入数据保证有解
输入输出样例
输入样例1
5 5 XX.XX X.X.X .XXX. X.X.X XX.XX
输出样例1
5
输入样例2
8 9 ..XXXXX.. .X.....X. X..X.X..X X.......X X.X...X.X X..XXX..X .X.....X. ..XXXXX..
输出样例2
25
解题思路
最开始的时候,我想的是和翻棋子,枚举全部的棋子,但最大为17,肯定会炸,所以我们还是搜一遍图,以棋子作为深度,先枚举第一排的射还是不射,之后第二排到n-1排都是为满足前一排一样(擦屁股),最后一排再看是不是一样的,是就更新就好了。
题解
1 #include <bits/stdc++.h> 2 using namespace std; 3 int n,m,ans=99999,sum; 4 int flag[29],b[29][29],mp[29][29]; 5 void fan(int x,int y)//射枪的操作 6 { 7 8 b[x][y]=!b[x][y]; 9 b[x-1][y]=!b[x-1][y]; 10 b[x+1][y]=!b[x+1][y]; 11 b[x][y-1]=!b[x][y-1]; 12 b[x][y+1]=!b[x][y+1]; 13 sum++;//步数加加 14 } 15 void dfs(int dep)//搜索,深度以棋子个数 16 { 17 18 int f;//判断最后一排是否合格 19 if(dep==m+1)//第一排射完了 20 { 21 sum=0;//步数 22 for(int i=1;i<=n;i++) 23 { 24 for(int j=1;j<=m;j++) 25 { 26 b[i][j]=mp[i][j];//复制图一遍 27 } 28 } 29 for(int i=1;i<=m;i++) 30 { 31 if(flag[i]==1)//标记了翻就翻 32 fan(1,i); 33 } 34 for(int i=2;i<=n;i++) 35 { 36 for(int j=1;j<=m;j++) 37 { 38 if(b[i-1][j]==1)//为上一排的擦屁股 39 fan(i,j); 40 } 41 } 42 for(int i=1;i<=m;i++) 44 { 45 if(b[n][i]==1)//如果是凸着的 46 f=0; //标记 47 } 48 if(f&&sum<ans) 49 ans=sum;//标记 50 return; 51 } 52 flag[dep]=0;//看射不射 53 dfs(dep+1); 54 flag[dep]=1; 55 dfs(dep+1); 56 } 57 int main() 58 { 59 cin>>n>>m; 60 for(int i=1;i<=n;i++) 61 { 62 for(int j=1;j<=m;j++) 63 { 64 char c; 65 cin>>c; 66 if(c=='X')//存图 67 mp[i][j]=1; 68 else 69 mp[i][j]=0; 70 } 71 } 72 dfs(1);//搜索 73 cout<<ans; 74 return 0; 75 }