杭州现场赛的题目,虽然大神们都说水,但我感觉还是不错的,还适合我这个水平做。
用bfs求出各个宝物之间的最短距离以及和Dudely之间的距离,然后用dfs枚举Dudely访问各个宝物的顺序,最后比较出距离和的最小值即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#define INF 2139062143
#define MAXN 105
using namespace std;
char grid[MAXN][MAXN];
int flag[MAXN][MAXN],N,M,n,ans,x[5],y[5],dis[5][5];
bool used[10],vis[MAXN][MAXN];
int MM[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
struct Point
{
int x,y,step;
Point(int a,int b,int c):x(a),y(b),step(c) {}
};
void bfs(int xx,int yy)
{
int cur=flag[xx][yy];
queue<Point> q;
memset(vis,0,sizeof(vis));
q.push(Point(xx,yy,0));
vis[xx][yy]=true;
while(!q.empty())
{
Point u=q.front();
q.pop();
for(int i=0; i<4; ++i)
{
int ta=u.x+ MM[i][0],tb=u.y+MM[i][1];
if(ta<1||tb<1||ta>N||tb>M) continue;
if(vis[ta][tb]||grid[ta][tb]=='#') continue;
vis[ta][tb]=true;
if(flag[ta][tb]!=-1)
dis[cur][flag[ta][tb]]=u.step+1;
q.push(Point(ta,tb,u.step+1));
}
}
}
void dfs(int now,int res,int cur)
{
if(cur==n)
ans=min(ans,res);
else
{
for(int i=1; i<=n; ++i)
if(!used[i]&&dis[now][i]<INF)
{
used[i]=true;
dfs(i,res+dis[now][i],cur+1);
used[i]=false;
}
}
}
int main()
{
while(scanf("%d%d",&N,&M)&&!(!N&&!M))
{
memset(flag,-1,sizeof(flag));
memset(grid,0,sizeof(grid));
memset(used,0,sizeof(used));
memset(dis,0x7f,sizeof(dis));
for(int i=1; i<=N; ++i)
scanf("%s",grid[i]+1);
for(int i=1; i<=N; ++i)
for(int j=1; j<=M; ++j)
if(grid[i][j]=='@')
{
x[0]=i;
y[0]=j;
flag[i][j]=0;
break;
}
scanf("%d",&n);
for(int i=1; i<=n; ++i)
{
scanf("%d%d",&x[i],&y[i]);
flag[x[i]][y[i]]=i;
}
for(int i=0; i<=n; ++i)
bfs(x[i],y[i]);
ans=INF;
dfs(0,0,0);
if(ans==INF) printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}