您的位置:首页 > 其它

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好题心得
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ACM 优先队列 bfs 广搜 hdu