UVa 1600-Patrol Robot题解
2015-08-14 19:10
288 查看
这题的题目不再赘述,题目链接https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4475。
题目意思和解题思路都很明显,用BFS求点到点的单源最短路径。但是不同的是:有些格子有障碍,但是又不能连续地穿过k个障碍。所以解题的关键就变成了如何判断当前层次访问的格子穿过的障碍小于等于k。我用了两种相似的思路来解这道题。 先说第一种。不多说,总体BFS。格子数据结构定义有x(横坐标)、y(纵坐标)、level(层次,用于得出最短路径)、layer(穿过的障碍层数)。首先由上层格子遍历周围四个方向的格子(得到当前格子),并判断坐标是否合法。然后判断该格子是否已经访问。接着判断当前层次访问格子穿过障碍是否小于等于k:首先判断当前格子是否有障碍,如果没有,layer为0;如果有,则layer等于上一层格子的layer+1。将格子入队。最后设置当前格子已经访问。代码如下:
#include<cstdio> #include<cstdlib> #include<cstring> #include<queue> using namespace std; struct Vertex { int x; int y; int level; int layer; Vertex(int _x,int _y,int le,int la):x(_x),y(_y),level(le),layer(la){}; };//格子的数据结构定义 const int maxn=25; int T; int m,n; int k; int map[maxn][maxn]; int visited[maxn][maxn]; int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};//二维向量,格子在四个方向上的坐标增量 int BFS() { int i; queue<Vertex> qu; qu.push(Vertex(0,0,1,0)); visited[0][0]=1; while(!qu.empty()) { Vertex v=qu.front(); qu.pop(); if(v.x==m-1&&v.y==n-1) return v.level-1; for(i=0;i<4;i++) { int dx=v.x+dir[i][0]; int dy=v.y+dir[i][1]; if(dx>=0 && dx<m && dy>=0 && dy<n) {//坐标合法 if(visited[dx][dy]==0) {//该点尚未访问 visited[dx][dy]==1; if(map[dx][dy]==0) {//没有障碍 qu.push(Vertex(dx,dy,v.level+1,0)); } else {//有障碍 if((v.layer+1)<=k) { qu.push(Vertex(dx,dy,v.level+1,v.layer+1)); } } } } } } return -1; } int main() { freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); scanf("%d",&T); while(T--) { memset(visited,0,sizeof(visited)); scanf("%d%d",&m,&n); scanf("%d",&k); int i; int j; for(i=0;i<m;i++) { for(j=0;j<n;j++) scanf("%d",&map[i][j]); } printf("%d\n",BFS()); } }
第二种方法。整体思路和第一种非常相似。但是,这里的visited访问数组增加了一个维度,变成了三维的。第三个维度表示的意思是穿过的障碍层数。这种方法似乎不是很好理解。不妨把它想象成一幢只打好地基房子。最表面的砖头就是一个个的格子,并且标明了是否有障碍。接着要做的就是在地基之上堆砌砖头。如果砖头上表明没有障碍,就不往上堆砖头(如果上面有多余一个的砖头的话就把上面的砖头都扔了);如果有障碍,就在当前格子上以前一个格子的砖头数为基础再增加一个砖头。但是堆的砖头数不能超过k个。代码如下:
#include<cstdio> #include<cstdlib> #include<cstring> #include<queue> using namespace std; struct Vertex { int x; int y; int level; int layer; Vertex(int _x,int _y,int le,int la):x(_x),y(_y),level(le),layer(la){}; };//格子的数据结构定义 const int maxn=25; int T; int m,n; int k; int map[maxn][maxn]; int visited[maxn][maxn][maxn];//visited增加了一个维度 int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}}; int BFS() { int i; queue<Vertex> qu; qu.push(Vertex(0,0,1,0)); visited[0][0][0]=1; while(!qu.empty()) { Vertex v=qu.front(); qu.pop(); if(v.x==m-1&&v.y==n-1) return v.level-1; for(i=0;i<4;i++) { int dx=v.x+dir[i][0]; int dy=v.y+dir[i][1]; int layer=v.layer; if(dx>=0 && dx<m && dy>=0 && dy<n) {//坐标合法 if(map[dx][dy]==0) layer=0;//格子没有障碍 else layer++; if(layer<=k && visited[dx][dy][layer]==0) {//穿过的障碍层数小于等于k并且尚未访问 qu.push(Vertex(dx,dy,v.level+1,layer)); } visited[dx][dy][layer]=1;//置为已访问 } } } return -1; } int main() { freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); scanf("%d",&T); while(T--) { memset(visited,0,sizeof(visited)); scanf("%d%d",&m,&n); scanf("%d",&k); int i; int j; for(i=0;i<m;i++) { for(j=0;j<n;j++) scanf("%d",&map[i][j]); } printf("%d\n",BFS()); } }
两种方法的思路都几乎相同。而且都基于BFS。所以算法的时间复杂度大致也应该是一个量级的才对。不过为什么第一种方法TLE了,我到现在都还没明白,欢迎各位路过的给我留言。本人不打ACM,刷题纯粹是为了学习算法的需要。所以很多东西都不是很懂,欢迎指教。
相关文章推荐
- Hibernate将sql查询结果中字符转为char类型的原因
- OC - Method(High)
- SDNU 1125 HDU 1004 Let the Balloon Rise【用map做水题】【map应用】 【8月14】
- Android自定义控件之乱涂
- C# odbc
- 大头小头 字节序
- 华为OJ(矩阵乘法)
- Quartz源码分析(二)
- Python学习笔记23:Django构建一个简单的博客网站(一个)
- 九度oj 1030
- hdu 1171 Big Event in HDU 多重背包问题
- Android常用的一些make命令
- VC和gcc在保证功能static对线程安全的差异变量
- Ampzz 2011 Cross Spider 计算几何
- java:可变类StringBuffer与不可变类String
- VisualSVN5.0.1补丁原创发布
- 拓扑排序模板-优先队列 hdu 1285 确定比赛名次
- POJ 1181 大整数是否为素数以及求大整数的质因数-数论-(Miller_rabin+Pollard_rho)
- 最小生成树prim算法实现
- HDU 1232 畅通工程