hrbust 1286/哈理工oj 1286 迷宫与宝藏【较难bfs】
来源:互联网 发布:java获取本地磁盘文件 编辑:程序博客网 时间:2024/05/23 10:05
迷宫有以下几种元素:
【*】 机器人的起点
【#】 墙。机器人不能走过这些格子
【.】 平地。机器人可以在上面自由行走
【0-9】 宝藏。当机器人走到此处会立刻获得该数字相应的宝藏,宝藏不会消失,可以反复获取(但不能停留)
若机器人要恰好获得总和为x的宝藏,它最少需要多少时间?
Input第一行输入任务数量T, 接下来有T个任务每块第一行有两个整数, n(0 <
100), m(0 < 100), 表示迷宫有n+1行和m+1列
接下来n行输入迷宫
最后一行输入你要收集的宝藏的总价值x(x ≤ 100)Output对于每个任务,输出最少花费的时间,如果完成不了该任务则输出-1Sample Input32 3
1.#2
#..#
*.#.
3
2 3
2.#2
#..#
*.#.
5
2 3
2.#2
#.3#
*.#.
5Sample Output8-1
6
做过不少这样的带着宝贝走的图搜的题、可惜这个题卡时间卡的太狠、剪枝无果、换思路、卡内存、优化代码、无果。如果是条件再放松一点点、这个题就好A多了、真的是一道很好的题目、卡时间,数据,内存具备、而且还有一个坑点、这里一会说(虽然找到了,但是还是没能AC)、最后还是看的大牛代码,找到了最终优化的方法、
首先呢,这里的路是可以重复行走的,但是行走重复的时候一定要保证身上带的东西的数量不同,要不然没有重复走这个路的必要、所以这里vis数组是三维的
分别存三个值,x,y,v(宝藏的价值)、
然后就bfs遍历就行了、优化几个小小的点:
1.起始点要注意是可以重复行走的、
2.如果当前走到的地方的宝藏数量大于了目标量,continue;
3.不用优先队列会超时、用了优先队列会超内存、、、、、妈了个巴子,不让人过个好年,好歹也是除夕,能不能愉快的玩耍了;
然后贴上我的思路的代码,一会和大牛的对比:
#include<stdio.h>#include<string.h>#include<queue>using namespace std;struct zuobiao{ int x,y,output; int cur; /*friend bool operator <(zuobiao a,zuobiao b) { return a.cur>b.cur; }*/}now,nex;char a[101][101];int vis[101][101][101];int fx[4]={0,0,1,-1};int fy[4]={1,-1,0,0};int n,m;int mubiao;void bfs(int x,int y){ queue<zuobiao >s; //priority_queue<zuobiao>s; memset(vis,0,sizeof(vis)); vis[0][x][y]=1; now.x=x; now.y=y; now.output=0; now.cur=0; s.push(now); while(!s.empty()) { now=s.front(); s.pop(); for(int i=0;i<4;i++) { nex.x=now.x+fx[i]; nex.y=now.y+fy[i]; nex.output=now.output; nex.cur=now.cur; if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&vis[nex.output][nex.x][nex.y]==0&&a[nex.x][nex.y]!='#') { if(a[nex.x][nex.y]=='.') { nex.cur++; vis[nex.output][nex.x][nex.y]=1; s.push(nex); } if(a[nex.x][nex.y]>='0'&&a[nex.x][nex.y]<='9') { nex.cur++; nex.output+=a[nex.x][nex.y]-'0'; //printf("%d\n",nex.output); if(nex.output==mubiao) { printf("%d\n",nex.cur); return ; } if(nex.output>mubiao) continue; vis[nex.output][nex.x][nex.y]=0; s.push(nex); } } } } printf("-1\n"); return ;}int main(){ int t; scanf("%d",&t); while(t--) { scanf("%d %d%",&n,&m); n++; m++; int x,y; for(int i=0;i<n;i++) { scanf("%s",a[i]); for(int j=0;j<m;j++) { if(a[i][j]=='*') { x=i; y=j; a[i][j]='.'; } } } scanf("%d",&mubiao); if(mubiao==0) { printf("0\n"); continue; } bfs(x,y); }}
以上是我的代码和简单叙述的思路、可惜怎么做都不能AC掉、水平实力还是不够啊....................T T
然后我们来说大牛的代码:大牛博客传送门:http://www.cnblogs.com/-hsz/archive/2012/11/09/2762050.html
首先,他的思路是这样的:把*和.都变成0
int x,y; for(int i = 0; i < n; i++) { scanf("%s",map[i]); for(int j=0; j<m; j++) { if(map[i][j]=='*') { map[i][j]='0'; x=i; y=j; } if(map[i][j]=='.') { map[i][j]='0'; } } }
然后考虑时间最优,这里咱俩的做题思路是一样的,但是我的超内存、(因为我的队列里边存的东西太多了、剪枝无果)他的没有,他是怎么做的呢?
他用一个vis【】【】【】表示:行,列,价值,记录最小步数。那么他是如何保证是最小步数的呢?
我们对应代码来看:
int vis[101][101][101]; //行,列,价值。vis记录最小步数。首先对他初始化为INT_MAX(其实初始化足够大就行,不用这么完美)char map[101][101];int n, m, mubiao;struct zuobiao{ int x, y, v;}now,nex;int fx[4]={0,0,1,-1};int fy[4]={1,-1,0,0};int bfs(int x,int y){ now.x=x; now.y=y; now.v=0; vis[now.x][now.y][now.v] = 0; queue<struct zuobiao> s; s.push(now);//起点入队 while(!s.empty()) { struct zuobiao now=s.front(); s.pop(); for(int i = 0; i < 4; i++) { nex.x = now.x + fx[i]; nex.y = now.y + fy[i]; if(nex.x >= 0 && nex.x < n && nex.y >= 0 && nex.y < m && map[nex.x][nex.y] != '#')//符合条件的走向 { nex.v = now.v + map[nex.x][nex.y] - '0';//宝藏入身、 if(nex.v == mubiao) return vis[now.x][now.y][now.v] + 1;//如果达到了目标数,输出 if(nex.v > mubiao) continue;//剪枝 if(vis[nex.x][nex.y][nex.v] > vis[now.x][now.y][now.v] + 1)//这里注意 ,很完美的语句,既达到了优先队列的效果(但是也不能说完全一样),也达到了时间数组的作用、注意初始化很大、 { vis[nex.x][nex.y][nex.v] = vis[now.x][now.y][now.v] + 1; s.push( nex ); } } } } return -1;}然后上完整的AC代码:
#include<stdio.h>#include<limits.h>#include<string.h>#include<queue>using namespace std;int vis[101][101][101]; //行,列,价值。vis记录最小步数。char map[101][101];int n, m, mubiao;struct zuobiao{ int x, y, v;}now,nex;int fx[4]={0,0,1,-1};int fy[4]={1,-1,0,0};int bfs(int x,int y){ now.x=x; now.y=y; now.v=0; vis[now.x][now.y][now.v] = 0; queue<struct zuobiao> s; s.push(now); while(!s.empty()) { struct zuobiao now=s.front(); s.pop(); for(int i = 0; i < 4; i++) { nex.x = now.x + fx[i]; nex.y = now.y + fy[i]; if(nex.x >= 0 && nex.x < n && nex.y >= 0 && nex.y < m && map[nex.x][nex.y] != '#') { nex.v = now.v + map[nex.x][nex.y] - '0'; if(nex.v == mubiao) return vis[now.x][now.y][now.v] + 1; if(nex.v > mubiao) continue; if(vis[nex.x][nex.y][nex.v] > vis[now.x][now.y][now.v] + 1) { vis[nex.x][nex.y][nex.v] = vis[now.x][now.y][now.v] + 1; s.push( nex ); } } } } return -1;}int main(){ int T; scanf("%d", &T); while( T-- ) { scanf("%d %d", &n, &m); n++; m++; for(int i = 0; i < n; i++) { for(int j = 0; j < m; j++) { for(int k = 0; k < 101; k++) { vis[i][j][k] =0x1f1f1f1f; } } } int x,y; for(int i = 0; i < n; i++) { scanf("%s",map[i]); for(int j=0; j<m; j++) { if(map[i][j]=='*') { map[i][j]='0'; x=i; y=j; } if(map[i][j]=='.') { map[i][j]='0'; } } } scanf("%d", &mubiao); if(mubiao == 0) { printf("0\n"); } else { printf("%d\n", bfs(x,y)); } } return 0;}
- hrbust 1286/哈理工oj 1286 迷宫与宝藏【较难bfs】
- 哈理工OJ 1286迷宫宝藏(这个bfs有点意思)
- hrbust 哈理工oj 1613 迷宫问题 bfs
- 迷宫与宝藏(bfs)
- hrbust/哈理工oj 1617 回家【BFS+BFS】
- hrbust 哈理工OJ 1498Elevator Trouble【BFS过】
- hrbust 哈理工oj 2188 星际旅行【BFS+传送阵】
- hrbust 哈理工oj 1989 营救小组【BFS】
- hrbust/哈理工oj 1495 Robots on a grid【BFS+BFS+dp】
- hrbust 1214 哈理工oj 1214 方格取数【BFS广搜+dp】
- hrbust 哈理工oj 1588 神医【贪心】
- hrbust 哈理工oj 网线【MST+Prim】
- 哈理工oj/hrbust 1790 武林【DP】
- hrbust哈理工oj 1674 充电【贪心】
- hrbust 哈理工oj 1330 邂逅【模拟】
- hrbust/哈理工oj 1877 区间【水题】
- 哈理工OJ 1525 水神(海上葬礼)(【BFS(较困难)】)
- Hrbust oj/哈理工 oj 1216数的划分
- 读卡器项目总结(一)— 总汇
- Bestcoder Round #71 HDU 5620 5621 5622 5623 5624
- c++引用类型小问题
- UVA 120 Stacks of Flapjacks 煎饼
- c++引用类型小问题
- hrbust 1286/哈理工oj 1286 迷宫与宝藏【较难bfs】
- IoGetNextIrpStackLocation routine
- FUSE源码剖析
- HDU 1074
- HDU 5621 KK's Point
- FUSE简介(译)
- WMI技术介绍和应用——Event Provider
- WC2016总结
- 1.3线性回归之线性回归实例