hdu 3345 War Chess(广搜,用不用优先队列都可以)
2017-07-21 11:44
549 查看
War Chess
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2929 Accepted Submission(s): 733
Problem Description
War chess is hh's favorite game:
In this game, there is an N * M battle map, and every player has his own Moving Val (MV). In each round, every player can move in four directions as long as he has enough MV. To simplify the problem, you are given your position and asked to output which grids
you can arrive.
In the map:
'Y' is your current position (there is one and only one Y in the given map).
'.' is a normal grid. It costs you 1 MV to enter in this gird.
'T' is a tree. It costs you 2 MV to enter in this gird.
'R' is a river. It costs you 3 MV to enter in this gird.
'#' is an obstacle. You can never enter in this gird.
'E's are your enemies. You cannot move across your enemy, because once you enter the grids which are adjacent with 'E', you will lose all your MV. Here “adjacent” means two grids share a common edge.
'P's are your partners. You can move across your partner, but you cannot stay in the same grid with him final, because there can only be one person in one grid.You can assume the Ps must stand on '.' . so ,it also costs you 1 MV to enter this grid.
Input
The first line of the inputs is T, which stands for the number of test cases you need to solve.
Then T cases follow:
Each test case starts with a line contains three numbers N,M and MV (2<= N , M <=100,0<=MV<= 65536) which indicate the size of the map and Y's MV.Then a N*M two-dimensional array follows, which describe the whole map.
Output
Output the N*M map, using '*'s to replace all the grids 'Y' can arrive (except the 'Y' grid itself). Output a blank line after each case.
Sample Input
5
3 3 100
...
.E.
..Y
5 6 4
......
....PR
..E.PY
...ETT
....TT
2 2 100
.E
EY
5 5 2
.....
..P..
.PYP.
..P..
.....
3 3 1
.E.
EYE
...
Sample Output
...
.E*
.*Y
...***
..**P*
..E*PY
...E**
....T*
.E
EY
..*..
.*P*.
*PYP*
.*P*.
..*..
.E.
EYE
.*.
这题不是坑点挺多的,而是需要的优化的地方蛮多的。网上大部分都是直接用优先队列做的,其实上来就去思考优先队列的精妙之处确实并不是那么简单,我先写了一个普通队列版本的(当然可以AC),里面包含了所有优先队列所能优化的点,可以先看一下,具体内容代码里说。
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<stack> #include<cstring> using namespace std; typedef long long ll; char map[105][105];//原始图 char omap[105][105];//记录*的图 int n,m,sum; int book[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};//四个方位 int vis[105][105];//记录每个点所剩最大mv值 int flag[105][105];//记录那些根本不需要走的点 int num[105][105];//记录在队列里面有几个这个点的元素并试试更新(不懂往后看) typedef struct { int x; int y; } node; bool enemy(int x,int y)//判断周围有没有E { int j; for(j = 0;j< 4;j++) { int txx = x+book[j][0]; int tyy = y+book[j][1]; if(map[txx][tyy] == 'E') { flag[x][y] = 1; break; } } if(j == 4) return 1; else return 0; } queue<node> q;//申请队列 void bfs(int sx,int sy) { node s; s.x = sx; s.y = sy; q.push(s); vis[sx][sy] = sum;//初始点的mv值是全部的mv num[sx][sy] = 1;//初始点有一个在队列里 while(!q.empty()) { node t = q.front(); q.pop(); if(num[t.x][t.y]> 1)//如果在队列里不只有1个这个点,而且最后那个mv值才是最大的,所以这个直接pop掉不要了 { num[t.x][t.y]--; continue; } num[t.x][t.y]--;//如果过了前边的判断条件不比1大,说明这就是最后那个 node temp; for(int i = 0;i< 4;i++) { int tx = t.x+book[i][0]; int ty = t.y+book[i][1]; if(flag[tx][ty]||tx> n||tx< 1||ty> m||ty< 1)//注意第一个条件 continue; if(map[tx][ty] == '#') continue; if(map[tx][ty] == 'Y') continue; if(map[tx][ty] == '.') { if(vis[t.x][t.y]-1< vis[tx][ty])//只有将要到达的点到这个点后的mv值比现在的mv值大才能替代 continue; omap[tx][ty] = '*';//标记为* if(vis[t.x][t.y]-1 == 0)//如果到这一点没能量了就不用压进队列里了 { flag[tx][ty] = 1; continue; } vis[tx][ty] = vis[t.x][t.y]-1; //更新最大值 temp.x = tx; temp.y = ty; flag[tx][ty] == 1;//标记为1 if(enemy(tx,ty))//判断周围有没有E,没有的话才能压进队列 { q.push(temp); num[tx][ty]++; } continue; } if(map[tx][ty] == 'T')//道理同上 { if(vis[t.x][t.y]-2< vis[tx][ty]) continue; omap[tx][ty] = '*'; if(vis[t.x][t.y]-2 == 0) { flag[tx][ty] == 1; continue; } vis[tx][ty] = vis[t.x][t.y]-2; temp.x = tx; temp.y = ty; flag[tx][ty] == 1; if(enemy(tx,ty)) { q.push(temp); num[tx][ty]++; } continue; } if(map[tx][ty] == 'R') { if(vis[t.x][t.y]-3< vis[tx][ty]) continue; omap[tx][ty] = '*'; if(vis[t.x][t.y]-3 == 0) { flag[tx][ty] == 1; continue; } vis[tx][ty] = vis[t.x][t.y]-3; temp.x = tx; temp.y = ty; flag[tx][ty] == 1; if(enemy(tx,ty)) { q.push(temp); num[tx][ty]++; } continue; } if(map[tx][ty] == 'P') { if(vis[t.x][t.y]-1< vis[tx][ty]) continue; if(vis[t.x][t.y]-1 == 0) { flag[tx][ty] == 1; continue; } vis[tx][ty] = vis[t.x][t.y]-1; temp.x = tx; temp.y = ty; flag[tx][ty] == 1; if(enemy(tx,ty)) { q.push(temp); num[tx][ty]++; } continue; } } } } int main() { int t; scanf("%d",&t); while(t--) { memset(vis,0,sizeof(vis)); memset(omap,0,sizeof(omap)); memset(flag,0,sizeof(flag)); memset(num,0,sizeof(num)); memset(map,0,sizeof(map)); int sx,sy; scanf("%d %d %d",&n,&m,&sum); getchar();//注意此处 for(int i = 1;i<= n;i++) { for(int j = 1;j<= m;j++) { scanf("%c",&map[i][j]); if(map[i][j] == 'Y') sx = i,sy = j; } getchar();//注意此处 } bfs(sx,sy); for(int i = 1;i<= n;i++) { for(int j = 1;j<= m;j++) { if(omap[i][j] == '*') printf("*"); else printf("%c",map[i][j]); } printf("\n"); } printf("\n"); } return 0; }
只要是想的明白就能做出来,如果想的明白用优先队列就更能明白了。(这个题用优先队列真是精妙至极!)
①优先队列可以保证每次行动的都是mv值最大的那个,也就是根本不用去维护每个点的最大mv值
②所有点只需要走一遍,标记一下下次走到这里直接continue
太精秒了!
上代码:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<stack> #include<cstring> using namespace std; typedef long long ll; char map[105][105]; char omap[105][105]; int flag[105][105];//记录走没走过 int n,m,sum; int book[4][2] = {{0,1},{0,-1},{1,0},{-1,0}}; typedef struct { int mv; int x; int y; } node; bool operator < (node a,node b) { return a.mv< b.mv; } bool enemy(int x,int y)//判断周围是否有E { int j; for(j = 0;j< 4;j++) { int txx = x+book[j][0]; int tyy = y+book[j][1]; if(map[txx][tyy] == 'E') { flag[x][y] = 1; break; } } if(j == 4) return 1; else return 0; } priority_queue<node> q; void bfs(int sx,int sy) { node s; s.x = sx; s.y = sy; s.mv = sum; q.push(s); flag[sx][sy] = 1; while(!q.empty()) { node t = q.top(); q.pop(); node temp; for(int i = 0;i< 4;i++) { int tx = t.x+book[i][0]; int ty = t.y+book[i][1]; if(flag[tx][ty]||tx> n||tx< 1||ty> m||ty< 1) continue; if(map[tx][ty] == '.') { if(t.mv-1< 0) continue; omap[tx][ty] = '*'; if(t.mv-1 == 0) continue; temp.x = tx; temp.y = ty; temp.mv = t.mv-1; flag[tx][ty] = 1; if(enemy(tx,ty)) q.push(temp); continue; } if(map[tx][ty] == 'T') { if(t.mv-2< 0) continue; omap[tx][ty] = '*'; if(t.mv-2 == 0) continue; temp.x = tx; temp.y = ty; temp.mv = t.mv-2; flag[tx][ty] = 1; if(enemy(tx,ty)) q.push(temp); continue; } if(map[tx][ty] == 'R') { if(t.mv-3< 0) continue; omap[tx][ty] = '*'; if(t.mv-3 == 0) continue; temp.x = tx; temp.y = ty; temp.mv = t.mv-3; flag[tx][ty] = 1; if(enemy(tx,ty)) q.push(temp); continue; } if(map[tx][ty] == 'P') { if(t.mv-1<= 0) continue; if(t.mv-1 == 0) continue; temp.x = tx; temp.y = ty; temp.mv = t.mv-1; flag[tx][ty] = 1; if(enemy(tx,ty)) q.push(temp); continue; } if(map[tx][ty] == '#') continue; } } } int main() { int t; scanf("%d",&t); while(t--) { memset(omap,0,sizeof(omap)); memset(map,0,sizeof(map)); memset(flag,0,sizeof(flag)); int sx,sy; scanf("%d %d %d",&n,&m,&sum); getchar(); for(int i = 1;i<= n;i++) { for(int j = 1;j<= m;j++) { scanf("%c",&map[i][j]); if(map[i][j] == 'Y') sx = i,sy = j; } getchar(); } bfs(sx,sy); for(int i = 1;i<= n;i++) { for(int j = 1;j<= m;j++) { if(omap[i][j] == '*') printf("*"); else printf("%c",map[i][j]); } printf("\n"); } printf("\n"); } return 0; }
ACM好题心得
相关文章推荐
- hdu 2757 优先队列水题
- HDU 1026 Ignatius and the Princess I - BFS + 优先队列
- HDU 4857 逃生 【拓扑排序+反向建图+优先队列】
- hdu 2112 HDU Today 优先队列优化的Dijkstra+map
- hdu 1509队列优先
- hdu 5289 ST表+双指针或者优先队列或者multiset
- hdu 5695 Gym Class【拓扑排序+优先队列】
- hdu 1242 Rescue(优先队列 && 广搜BFS)
- 优先队列广搜 hdu 1242
- HDU - 1509 Windows Message Queue (优先队列 重载运算符)
- HDU 1873 看病要排队 【优先队列】
- HDU 6000 Wash (优先队列-贪心)
- HDU 1026 Ignatius and the Princess I (bfs + 优先队列 + 路径记录)
- hdu 2364 Escape【模拟优先队列】【bfs】
- HDU 4857 逃生(拓扑排序,优先队列,容器)
- hdu 1874 畅通工程续 (Dijkstra + 优先队列优化)
- HDU 1058 Humble Numbers【巧用优先队列】
- hdu1242 Rescue(BFS +优先队列 or BFS )
- hdu 4006 优先队列 2011大连赛区网络赛F **
- 杭电OJ——1058 Humble Numbers(用优先队列也可以解)