题目
思路
这道题有一句话特别难懂:帮忙找出这样一条从V
到J
的路径,使得 Vjekoslav 在途中离它最近的树的距离的最小值最大。
最近 最小值 最大 我直接晕了
分析一下:
- 最近:t棵树中最近的那棵tree。
- 最小值:离tree最近的那个点p和tree的距离。
- 最大:使p和tree的距离最大。
意思就是,选择一条v到j的路径,使路上的每个点都和树离得越远越好。
代码
注释多多;数据结构和思路都写得比较详细。
#include<bits/stdc++.h>
using namespace std;
char g[505][505];
int mhd[505][505],vis[505][505];
int n,m;
//用于存储点信息,更新曼哈顿距离
struct node{
int x,y,d;
};
struct wolf{
int x,y,d;
//降序,为了使狼到树的距离越远越好
bool operator < (const wolf w)const
{
return w.d>d;
}
}start,endj;
//队列q:用于计算所有定点到最近的树的曼哈顿距离
queue <node> q;
//优先队列q:根据d降序入队,为了走离树更远的路径
priority_queue <wolf> p;
int xd[4]={0,0,1,-1};
int yd[4]={1,-1,0,0};
//预处理曼哈顿 距离 打表
void bfs1()
{
while(!q.empty())
{
node cur=q.front();
q.pop();
//四个方向都走一格,如果没走过就
for(int i=0;i<4;i++)
{
int xn=cur.x+xd[i];
int yn=cur.y+yd[i];
//注意一下x是行,y是列
//如果点在图内且未被访问,更新其曼哈顿距离
//因为是从树开始扩散开,所以可以保证是层次遍历,越早遍历到曼哈顿距离最短
if(0<=xn&&xn<n&&0<=yn&&yn<m&&!vis[xn][yn])
{
mhd[xn][yn]=cur.d+1;
//cout<<"x="<<xn<<"y="<<yn<<"mhd:"<<mhd[xn][yn]<<endl;
q.push(node{xn,yn,mhd[xn][yn]});
vis[xn][yn]=1;
}
}
}
}
//起始点先入队,然后bfs
//由于bfs是层次遍历,因此到终点的路线是较短的
//优先队列的性质告诉我们每次队首都是队列离树最远的节点
int bfs2()
{
memset(vis,0,sizeof(vis));
start.d=mhd[start.x][start.y];
p.push(start);
vis[start.x][start.y]=1;
while(!p.empty())
{
wolf cur=p.top();
p.pop();
//cout<<"pop:x="<<cur.x<<"y:"<<cur.y<<"d:"<<cur.d<<endl;
if(cur.x==endj.x&&cur.y==endj.y)
{
//cout<<"终点到!";
return cur.d;
break;
}
for(int i=0;i<4;i++)
{
int xn=cur.x+xd[i];
int yn=cur.y+yd[i];
//
if(0<=xn&&xn<n&&0<=yn&&yn<m&&!vis[xn][yn])
{
//cout<<"push:x="<<xn<<"y="<<yn<<"d:"<<min(mhd[xn][yn],cur.d)<<endl;
p.push(wolf{xn,yn,min(mhd[xn][yn],cur.d)});
vis[xn][yn]=1;
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>g[i][j];
if(g[i][j]=='+')
{
node a;
a.x=i;a.y=j;a.d=0;
q.push(a);
vis[i][j]=1;
//树上的曼哈顿距离是0;
mhd[i][j]=0;
}
else if(g[i][j]=='V')
{
start.x=i;
start.y=j;
}
else if(g[i][j]=='J')
{
endj.x=i;
endj.y=j;
}
}
}
//bfs可以遍历连通图
bfs1();
cout<<bfs2();
}