题意是给你一个起点@,.为可走,#为不可走,再给你一些宝藏的坐标,问取完这些宝藏需要的最短距离是多少,如果不能输出-1.
个人认为模拟题最重要的是划分步骤,现在我们来理一理这道题的步骤。
第一步寻找每一个宝藏点到下一个点的最短路,对于每个起点通过bfs实现。
第二步判断路径的先后顺序,这里可以通过dfs,进行2的n次方枚举,数据范围小便可以完成。
这就将一个模拟题拆分为两个子问题,一步一步写便可以完成。
下附AC代码。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
#define maxn 150
using namespace std;
struct nod
{
int x,y;
nod(int a,int b)
{
x=a;
y=b;
}
nod(){}
}val[maxn];
int n,m,qq,cnt;
queue<nod> q;
int ans=987654321;
int valnum[maxn][maxn];
int num[maxn][maxn];
char gra[maxn][maxn];
int vis[maxn][maxn][maxn];
int dis[maxn][maxn][maxn];
int fx[]={0,1,-1,0,0};
int fy[]={0,0,0,1,-1};
void bfs(int x,int y,int num)
{
while(!q.empty())
q.pop();
q.push(nod(x,y));
vis[num][x][y]=1;
dis[num][x][y]=0;
while(!q.empty())
{
nod now=q.front();
q.pop();
for(int i=1;i<=4;i++)
{
int nx=now.x+fx[i];
int ny=now.y+fy[i];
if(1<=nx && nx<=n && 1<=ny && ny<=m && gra[nx][ny]=='.' && vis[num][nx][ny]==0)
{
vis[num][nx][ny]=1;
dis[num][nx][ny]=dis[num][now.x][now.y]+1;
q.push(nod(nx,ny));
}
}
}
}
void dfs(int x,int y,int lef[],int now)
{
int flag=true;
for(int i=1;i<=qq;i++)
{
if(lef[i])
{
flag=false;
break;
}
}
if(flag==true)
{
ans=min(ans,now);
return;
}
for(int i=1;i<=4;i++)
if(lef[i])
{
int d=dis[valnum[x][y]][val[i].x][val[i].y];
if(d!=-1)
{
lef[i]=0;
dfs(val[i].x,val[i].y,lef,now+d);
lef[i]=1;
}
}
}
int main()
{
while(cin>>n>>m && (n||m))
{
ans=987654321;
memset(vis,0,sizeof(vis));
memset(dis,-1,sizeof(dis));
cnt=0;
int nx,ny;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>gra[i][j];
cnt++;
num[i][j]=cnt;
if(gra[i][j]=='@')
nx=i,ny=j;
}
valnum[nx][ny]=0;
bfs(nx,ny,0);
cin>>qq;
for(int i=1;i<=qq;i++)
{
int x,y;
cin>>x>>y;
val[i].x=x;
val[i].y=y;
valnum[x][y]=i;
bfs(x,y,i);
}
int temp[5];
for(int i=1;i<=4;i++)
temp[i]=1;
dfs(nx,ny,temp,0);
if(ans==987654321)
cout<<"-1"<<endl;
else
cout<<ans<<endl;
}
}