题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2612
题意:给一个m*n的图,求Y和M到图上所有的@的和的最小值。数据200*200
思路:一开始觉得可以每遇到一个@就bfs一次,更新其到Y和M的最小值,这样比较好些。后来考虑到极限情况下可能有很多@,复杂度会很高,所以转换到用两个dis二维数组存储Y和M到所有的@的距离,这样就可以只遍历两次就够了,另外可以设立一个vector存储所有@的位置,这样就不用再遍历一次整个图了(虽然并没有优化多少)。另外wa了一次才发现@亦可以当做路来走。
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <cstring>
#include <malloc.h>
#include <queue>
#include <map>
#include <set>
using namespace std;
const int maxn = 202;
const int inf = 0x3f3f3f3f;
char mat[maxn][maxn];
int dis1[maxn][maxn];
int dis2[maxn][maxn];
bool vis[maxn][maxn];
int d[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int n,m;
struct node
{
int x,y,st;
node(){}
node(int a,int b,int c):x(a),y(b),st(c){}
}ss,ns;
vector<node> res;
void bfs(int x,int y,int dis[][maxn])
{
memset(vis,0,sizeof(vis));
queue<node> que;
que.push(node(x,y,0));
while(que.size()){
ss=que.front();que.pop();
for(int i=0;i<4;i++){
int dx=ss.x+d[i][0];
int dy=ss.y+d[i][1];
if(dx<n&&dx>=0&&dy<m&&dy>=0){
if(!vis[dx][dy]&&mat[dx][dy]!='#')//不仅仅是.可以走,@也可以走
{
vis[dx][dy]=1;
que.push(node(dx,dy,ss.st+1));
}
if(mat[dx][dy]=='@'&&dis[dx][dy]==0)//第一次遇到的才是最短的,更新一次之后不再更新
{
dis[dx][dy]=ss.st+1;
}
}
}
}
return;
}
int main()
{
while(scanf("%d%d",&n,&m)!=-1){
getchar();
res.clear();
memset(mat,0,sizeof(mat));
memset(dis1,0,sizeof(dis1));
memset(dis2,0,sizeof(dis2));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
scanf("%c",&mat[i][j]);
if(mat[i][j]=='@') res.push_back(node(i,j,0));
if(mat[i][j]=='Y') ss=node(i,j,0);
if(mat[i][j]=='M') ns=node(i,j,0);
}
getchar();
}
bfs(ss.x,ss.y,dis1);
bfs(ns.x,ns.y,dis2);
int mi=inf;
for(int i=0;i<res.size();i++){
ns=res[i];
if(dis1[ns.x][ns.y]!=0&&dis2[ns.x][ns.y]!=0){
int tmp=dis1[ns.x][ns.y]+dis2[ns.x][ns.y];
if(mi>tmp) mi=tmp;
}
}
printf("%d\n",mi*11);
}
return 0;
}