题目的含义是,求从起点出发,经过k个点的最短路径长度。
因此,可以先将起点和k个点构造一个图,图之间的权重为两点之间的最短路径距离,这个距离可以使用bfs求得。
在构造出这个图之后,可以使用dfs进行一个遍历,求从起点出发,经过所有k个点的最小路径的长度。
本题对dfs和bfs都是一个很好的练习
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <queue>
using namespace std;
int n,m,sx,sy,k,res;
char graph[105][105];
bool vis[105][105];
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
struct Node{
int x,y;
}node[10];
struct node1{
int x,y,step;
};
int p[10][10];
int bfs(int from,int to){
memset(vis,0,sizeof(vis));
queue<node1> q;
node1 cur,next;
cur.x = node[from].x;
cur.y = node[from].y;
cur.step = 0;
q.push(cur);
vis[cur.x][cur.y] = 1;
while(!q.empty()){
cur = q.front();
q.pop();
if(cur.x==node[to].x && cur.y==node[to].y){
return cur.step;
}
for(int i=0;i<4;i++){
int xx = cur.x+dx[i];
int yy = cur.y+dy[i];
if(xx>=1 && xx<=n && yy>=1 && yy<=m && graph[xx][yy]!='#' && !vis[xx][yy]){
vis[xx][yy] = 1;
next.x = xx;
next.y = yy;
next.step = cur.step+1;
q.push(next);
}
}
}
return -1;
}
void dfs(int f[],int pre,int cost,int cnt){
if(cnt==k){
if(cost<res){
res = cost;
}
return ;
}
for(int i=1;i<=k;i++){
if(f[i]==0){
f[i] = 1;
dfs(f,i,cost+p[pre][i],cnt+1);
f[i] = 0;
}
}
}
int main(){
while(scanf("%d%d",&n,&m)){
if(n==0 && m==0) break;
memset(vis,false,sizeof(vis));
memset(graph,'#',sizeof(graph));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf(" %c",&graph[i][j]);
if(graph[i][j]=='@'){
sx = i;
sy = j; //记录起点
}
}
}
node[0].x = sx;
node[0].y = sy;
scanf("%d",&k);
for(int i=1;i<=k;i++)
scanf("%d%d",&node[i].x,&node[i].y);
memset(p,-1,sizeof(p));
bool flag = 0;
for(int i=0;i<=k;i++){ //枚举任意必须要经过的两点间的最短路径,用bfs求出来
p[i][i] = 0;
for(int j=0;j<=k;j++){
if(p[i][j]==-1 && flag==0){
p[i][j] = p[j][i] = bfs(i,j);
if(p[i][j]==-1){
flag = 1;
break;
}
}
}
}
if(flag){
printf("-1\n");
continue;
}
int f[10];
memset(f,0,sizeof(f));
res = INT_MAX;
dfs(f,0,0,0);
printf("%d\n",res);
}
return 0;
}