第六届蓝桥杯决赛真题 04 穿越雷区(dfs || bfs)
2017-05-22 23:17
429 查看
穿越雷区
Time Limit : 5000/3000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other)Total Submission(s) : 18 Accepted Submission(s) : 8
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
X星的坦克战车很奇怪,它必须交替地穿越正能量辐射区和负能量辐射区才能保持正常运转,否则将报废。某坦克需要从A区到B区去(A,B区本身是安全区,没有正能量或负能量特征),怎样走才能路径最短?
已知的地图是一个方阵,上面用字母标出了A,B区,其它区都标了正号或负号分别表示正负能量辐射区。
例如:
A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -
坦克车只能水平或垂直方向上移动到相邻的区。
Input
第一行输入一个整数T,表示测试数据的组数。接下来有T组数据,
输入第一行是一个整数n,表示方阵的大小, 4<=n<100
接下来是n行,每行有n个数据,可能是A,B,+,-中的某一个,中间用空格分开。
A,B都只出现一次。
Output
要求每行输出一个整数,表示坦克从A区到B区的最少移动步数。如果没有方案,则输出-1
Sample Input
1 5 A + - + - - + - - + - + + + - + - + - + B + - + -
Sample Output
10ps:无意中看到了这个题,感觉不错就写了一下,开始用的bfs,后来又用dfs做了一下,个人感觉还是用bfs好一点。
解题思路:请看注释,一定记得吃回车符吃空格符,博主本来直接敲好了代码,就是没吃回车符和空格符卡了好久。
代码1(bfs):
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; char mp[105][105]; bool vis[105][105]; //标记数组 bool flag; //标记是否找到合适的方案 int dir[4][2]= {{-1,0},{0,-1},{1,0},{0,1}};//搜索的四个方向 int n; int ans; int ex,ey; struct node { int x,y,step; } s,ns; void bfs(int x,int y) { int nx,ny; queue<node>q; s.x=x; s.y=y; s.step=0; vis[x][y]=false; q.push(s); //加入第一个点 while(!q.empty()) { s=q.front(); //弹出第一个点判断 q.pop(); //删除这个点 if(s.x==ex&&s.y==ey) //搜索到终点就返回 { ans=s.step; flag=true; return ; } for(int i=0; i<4; i++) { nx=s.x+dir[i][0]; ny=s.y+dir[i][1]; if(nx>=0&&nx<n&&ny>=0&&ny<n&&vis[nx][ny]) { if(mp[nx][ny]!=mp[s.x][s.y]) //这个节点与上一个节点符号不同才加入队列 { ns.x=nx; ns.y=ny; ns.step=s.step+1; vis[nx][ny]=false; //已经访问就标记为false //printf("push(%d,%d), d=%d\n", ns.x, ns.y, ns.step); q.push(ns); } } } } } int main() { int t; scanf("%d",&t); getchar(); //吃回车字符 while(t--) { int sx,sy; flag=false; memset(vis,true,sizeof(vis)); scanf("%d",&n); getchar(); //吃回车字符 for(int i=0; i<n; i++) for(int j=0; j<n; j++) { scanf("%c",&mp[i][j]); if(mp[i][j]=='A') { sx=i; sy=j; } if(mp[i][j]=='B') { ex=i; ey=j; } getchar(); //吃空格字符或回车符 } bfs(sx,sy); if(!flag) printf("-1\n"); else printf("%d\n",ans); } return 0; } /* 3 5 A + - + - - + - - + - + + + - + - + - + B + - + - 3 A + + + + + + + B 3 A + - + + + + + B 答案: 10 -1 4 */
解题思路:网上查到下面这种方法也可以解决空格符和回车符赋值给字符数组的问题,若使用以下输入语句,那么三个getchar()均可省略。
* 表示本输入项在读入后不赋值给相应的变量
在scanf中*被称为:附加格式说明符
scanf("%*c%c",&mp[i][j])
c语言中scanf格式化输入函数详解请点击
然后就是剪枝问题,不然就有可能超时,就是判断一下新路径已有长度是否比原来最短路是否长,是就没必要再找下去了。
代码2(dfs):
#include <iostream> #include <cstdio> #include <cstring> #define inf 0x3f3f3f3f //无穷大的一般定义 using namespace std; bool vis[105][105]; char mp[105][105]; int dir[4][2]= {{-1,0},{0,-1},{1,0},{0,1}}; int n,sx,sy,ex,ey; int ans; void dfs(int x,int y,int t) { int nx,ny; if(x==ex&&y==ey&&t<ans) //深搜找的是多组符合题意的而方案,取最优解 { ans=t; return; } for(int i=0; i<4; i++) { nx=x+dir[i][0]; ny=y+dir[i][1]; if(nx>=n||ny>=n||nx<0||ny<0||mp[nx][ny]==mp[x][y]||!vis[nx][ny]) continue; if(nx>=0&&ny>=0&&nx<n&&ny<n&&mp[nx][ny]!=mp[x][y]&&vis[nx][ny]) { vis[nx][ny]=false; if(t<ans) //剪枝,不然超时 dfs(nx,ny,t+1); vis[nx][ny]=true; } } } int main() { int t; scanf("%d",&t); while(t--) { ans=inf; memset(vis,true,sizeof(vis)); scanf("%d",&n); for(int i=0; i<n; i++) for(int j=0; j<n; j++) { scanf("%*c%c",&mp[i][j]); //*表示本输入项在读入后不赋值给相应的变量 if(mp[i][j]=='A') { sx=i; sy=j; } if(mp[i][j]=='B') { ex=i; ey=j; } } dfs(sx,sy,0); if(ans!=inf) printf("%d\n",ans); else printf("-1\n"); } return 0; }
相关文章推荐
- 2015第七届蓝桥杯决赛C语言A组--穿越雷区(DFS)
- 蓝桥杯 穿越雷区 2015年第六届蓝桥杯JavaB组决赛第四题
- 穿越雷区第六届蓝桥杯大赛个人赛决赛(C语言A组)第四题
- 蓝桥杯java第六届决赛第四题--穿越雷区
- 第六届蓝桥杯决赛 C语言A组 题解 第四题_穿越雷区
- 算法笔记_209:第六届蓝桥杯软件类决赛部分真题(Java语言B组)
- 算法笔记_208:第六届蓝桥杯软件类决赛真题(Java语言A组)
- 2015第六届蓝桥杯决赛--方格填数(DFS)
- 蓝桥杯之穿越雷区 BFS
- 2015蓝桥杯决赛Java A组 第四题--穿越雷区
- 蓝桥杯第六届决赛真题大全解(java版本)
- 2015年第六届蓝桥杯大赛个人赛决赛(软件类)真题 标题:方格填数
- 第六届蓝桥杯总决赛 穿越雷区
- 算法笔记_210:第六届蓝桥杯软件类决赛真题(Java语言C组)
- 蓝桥杯第六届国赛JAVA真题----表格计算
- 蓝桥杯 历届真题之剪格子(dfs)
- 蓝桥杯第六届省赛JAVA真题----循环节长度
- 蓝桥杯第六届省赛JAVA真题----打印菱形
- 2014年第五届蓝桥杯C/C++ C组决赛真题题解
- 第六届蓝桥杯决赛 C语言B组 题解 第五题_居民集会