NYOj-WAJUEJI which home strong!-BFS + 优先队列
来源:互联网 发布:java sql触发器写法 编辑:程序博客网 时间:2024/04/27 07:56
问题描述:
第一个数T,T组测试数据。
两个数 n, m; ( 0< n , m <= 100 ) 表示一个h行m列的二维地图。
接下来n行每行m 个字符。
‘s’ 表示弟弟目前所在位置。
‘# ’表示此处为一座山。为了节省体力,不从此处通行。
从‘A’-‘Z’表示各地的经济水平,对应1-26,路过对应字符的地区需要交对应的生活费。
‘l’表示蓝翔技校的所在地。
s 与 l 均为小写字母。
弟弟只能走四个方向。
代码①:DFS
char maze[110][110];//maze用来储存地图int book[110][110],mcost,n,m;void dfs(int x,int y,int cost)//走到点(x,y)时,路费为cost{ if(maze[x][y] == 'l')//边界 { cost -= 'l'- 'A' + 1;//将多加的路费减去 mcost = min(mcost,cost);//更新答案 return; } if(cost > mcost)//最优化剪枝,不过没什么用,依然T return; for(int i = 0; i <= 3; ++i)//上下左右 { int tx = x + dirx[i]; int ty = y + diry[i]; if(tx < 1 || tx > n || ty < 1 || ty > m)//越界 continue; if(maze[tx][ty] != '#' && book[tx][ty] == 0)//不是山且没被标记过 { book[tx][ty] = 1;//标记 dfs(tx,ty,cost + (int)maze[tx][ty] - 'A' + 1); book[tx][ty] = 0;//取消标记 } }}int main(){ int _, sx,sy; scanf("%d\n",&_);//输入数据组数 while(_--) { memset(book,0,sizeof(book));//重置标记数组 mcost = inf;//重置 //cin >> n >> m;// 玄学问题,用cin会出错 scanf("%d%d\n",&n,&m);//一定要加\n,否则会出错!!! for(int i = 1; i <= n; ++i)//输入地图 for(int j = 1; j <= m; ++j) { scanf("%1c\n",&maze[i][j]); if(maze[i][j] == 's') { sx = i;//记录起点 sy = j; } } book[sx][sy] = 1;//标记起点 dfs(sx,sy,0);//深度优先搜索 if(mcost == inf)//打印 cout << "-1" << endl; else cout << mcost << endl; } return 0;}
代码②:BFS(AC)
struct node//队列元素{ int x; int y; int cost;};queue<node>pq;//队列int maze[110][110];int mcost,n,m,book[110][110];node t,next_t;int main(){ int _, sx,sy; scanf("%d\n",&_); while(_--) {// for(int i = 1; i <= n; ++i)//错误,n,m还未被输入// for(int j = 1; j <= m; ++j)// book[i][j] = inf; scanf("%d%d\n",&n,&m);//加上\n //初始化 mcost = inf; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) book[i][j] = inf; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) { scanf("%1c\n",&maze[i][j]);//加上\n if(maze[i][j] == 's') { sx = i;//记录起点 sy = j; } } t.x = sx; t.y = sy; t.cost = 0; pq.push(t);//将起点入队 while(!pq.empty())//当队列非空 { t = pq.front();//出队 book[t.x][t.y] = t.cost;//将到达点(x,y)所花费的路费记为cost for(int i = 0; i <= 3; ++i)//上下左右 { next_t.x = t.x + dirx[i]; next_t.y = t.y + diry[i]; if(next_t.x < 1 || next_t.x > n || next_t.y < 1 || next_t.y > m)//越界 continue; if(maze[next_t.x][next_t.y] == '#')//山 continue; if(maze[next_t.x][next_t.y] == 'l')//终点 { mcost = min(mcost,t.cost);//更新答案 continue;//继续 } next_t.cost = t.cost + maze[next_t.x][next_t.y] - 'A' + 1;//计算到下一个点的路费 if(book[next_t.x][next_t.y] > next_t.cost)//如果到下一个点的路费大于其标记,则没有必要对其进行扩展 { book[next_t.x][next_t.y] = next_t.cost;//虽然入队后会修改标记,但是在这儿就修改会加速算法,险过 pq.push(next_t);//入队 } pq.pop();//出队 } } if(mcost == inf)//打印 cout << "-1" << endl; else cout << mcost << endl; } return 0;}
思考:这道题的关键点在标记上,如果不标记,程序会陷入死循环;而如果只标记为1,程序效率会很低下。不错的办法是将其标记为花费,如果以某种方式扩展而来的点的花费超过了当前的标记,则其没有被加入队列的必要
代码③:BFS + 优先队列(AC)
struct node//队列元素{ int x; int y; int cost;};struct cmp//自定义{ bool operator()(const node &a,const node &b) { return a.cost > b.cost;//较小的花费值排在前面 }};priority_queue<node,vector<node>,cmp> pq;char maze[110][110];int mcost,n,m,book[110][110],flag;node t,next_t;int main(){ int _, sx,sy; scanf("%d\n",&_); while(_--) { scanf("%d%d\n",&n,&m); //重置 flag = 0; mcost = inf; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) book[i][j] = inf; //读入地图 for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) { scanf("%1c\n",&maze[i][j]); if(maze[i][j] == 's') { sx = i;//记录起点 sy = j; } } t.x = sx; t.y = sy; t.cost = 0; pq.push(t);//将起点入队 while(!pq.empty()) { t = pq.top(); book[t.x][t.y] = t.cost;//记录 pq.pop();//需要尽快出队 for(int i = 0; i <= 3; ++i) { next_t.x = t.x + dirx[i]; next_t.y = t.y + diry[i]; if(next_t.x < 1 || next_t.x > n || next_t.y < 1 || next_t.y > m)//越界 continue; if(maze[next_t.x][next_t.y] == '#')//山 continue; if(maze[next_t.x][next_t.y] == 'l')//终点 { mcost = min(mcost,t.cost); //flag = 1;//错误 //break;//错误,不能直接break continue; } next_t.cost = t.cost + maze[next_t.x][next_t.y] - 'A' + 1; if(book[next_t.x][next_t.y] > next_t.cost) { book[next_t.x][next_t.y] = next_t.cost;//加速 pq.push(next_t);//入队 } } //if(flag == 1)//错误 //break; } if(mcost == inf)//打印 cout << "-1" << endl; else cout << mcost << endl; } return 0;}
解决方法:对比代码②和③,发现关键点还是标记的使用。用了优先队列,速度有了大幅的提升,但是还不够快。对照一下别人的代码,他找出第一组解后直接返回,而我还需要继续不断比较,如果直接返回的话,会WA。大概我写的是假的BFS + 优先队列吧……
代码④:标程
char maze[105][105];//地图int n,m,sx,sy,book[105][105];struct node{ int x; int y; int cost; friend bool operator < (const node &a,const node &b)//友元函数重载操作符 { return a.cost > b.cost; }};node t,next_t;int BFS(){ priority_queue<node> pq;//定义成局部变量!!!要么就每一次都将其清空,否则会影响接下来的数据 t.x = sx; t.y = sy; t.cost = 0; pq.push(t);//入队 book[t.x][t.y] = 1;//标记 while(!pq.empty()) { t = pq.top();//访问栈顶元素 pq.pop();//尽快出队 if(maze[t.x][t.y] == 'l')//如果当前点为终点 return t.cost;//直接返回 for(int i = 0; i <= 3; i++)//上下左右 { next_t.x = t.x + dirx[i]; next_t.y = t.y + diry[i]; next_t.cost = t.cost; if(next_t.x >= 1 && next_t.y >= 1 && next_t.x <= n && next_t.y <= m && book[next_t.x][next_t.y] == 0 && maze[next_t.x][next_t.y] != '#')//如果不越界、没被访问过、不是山 { if(maze[next_t.x][next_t.y] != 'l')//如果下一个点是终点,就不加其路费 next_t.cost = next_t.cost + maze[next_t.x][next_t.y] - 'A' + 1; pq.push(next_t);//入队 book[next_t.x][next_t.y] = 1;//标记 } } } return -1;//无解}int main(){ int _; scanf("%d\n",&_); while(_--) { memset(book,0,sizeof(book));//重置 scanf("%d%d\n",&n,&m); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { scanf("%1c\n",&maze[i][j]); if(maze[i][j] == 's') { sx = i;//记录起点 sy = j; } } int ans = BFS(); printf("%d\n",ans);//打印 }}
解决方法:标程只跑了112ms。它快就快在一到达终点,所花路费就是最小值。这是为什么呢?我们最初对起点进行扩展,扩展出来的点的路费由小到大在优先队列中排列,接下来再对堆顶的点进行扩展,就像几个小孩子嬉戏打闹你追我赶。最先到达终点的点所耗路费一定是最小的,否则先到达终点的就不是它了。这样一来,不必对所有路径、所有路费的值进行比较,节省了大量时间。
阅读全文
0 0
- NYOJ--1100 WAJUEJI which home strong!【BFS,优先队列】
- NYOJ - 1100 - WAJUEJI which home strong!(BFS变形,优先队列)
- NYOJ 1100 WAJUEJI which home strong!(BFS+优先队列)
- NYOJ 1100 WAJUEJI which home strong(BFS+优先队列)
- nyoj 1100 WAJUEJI which home strong!( BFS+优先队列)
- NYOj-WAJUEJI which home strong!-BFS + 优先队列
- NYOJ 题目1100 WAJUEJI which home strong!(BFS,优先队列)
- nyoj-1100-广搜+优先队列-WAJUEJI which home strong!
- NYOJ1100【WAJUEJI which home strong!】BFS+优先队列
- WAJUEJI which home strong!(BFS+优先队列)
- nyoj--1100--WAJUEJI which home strong!(bfs)
- NYOJ 1100-WAJUEJI which home strong!【bfs】
- BFS+优先级队列-WAJUEJI which home strong!
- NYOJ WAJUEJI which home strong!
- nyoj 1100 WAJUEJI which home strong! 【简单BFS】
- NYOJ 1100 WAJUEJI which home strong! (BFS)
- nyoj 1100 WAJUEJI which home strong!
- NYOJ 1100 WAJUEJI which home strong!
- POJ 1002 487-3279
- leetcode 501. Find Mode in Binary Search Tree
- POI
- [NOIP模拟] Road (并查集)
- Linux常用命令
- NYOj-WAJUEJI which home strong!-BFS + 优先队列
- 深入Log4J源码之Log4J Core
- 使用文件操作函数实现简单的CP、cat、size功能及读取文件内容初始化结构体
- 剑指offer第八题(跳台阶)
- Idear部署web项目过程
- JAVA实现年月日动态变化
- flume简单测试hdfssink && hivesink
- ZOJ
- python笔记