这题的题意是给你一幅图和几个点,问你从起点出发,把给你的点都跑到,最短的距离是多少。这里我们可以用bfs先处理每个点之间的最短距离(起点也算),然后写一个状态压缩DP,DP[ST][I],ST代表的是当前已经跑过的点, I代表的是最后一个跑道的点是哪个,那么状态转移方程就出来了,就是DP[ST1][K] = min(DP[ST1][K],DP[ST2][J] + DIS[J][K]).最后再在所有点都到的DP里找最小值就可以了.
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
#define maxn 100
#define inf 1000000005
#define mem(a, b) memset(a, b, sizeof(a))
using namespace std;
int n, m, num[maxn + 5][maxn + 5], dis[6][6], dp[1<<6][6], nn, k, ox[4] = {1, -1, 0, 0}, oy[4] = {0, 0, 1, -1};
char maps[maxn + 5][maxn + 5];
bool vis[maxn + 5][maxn + 5];
struct node
{
int x, y, dis;
}nd[6];
void bfs(int a)
{
mem(vis, 0);
queue<struct node> q;
vis[nd[a].x][nd[a].y] = 1;
nd[a].dis = 0;
q.push(nd[a]);
while(!q.empty())
{
struct node tmp = q.front();
q.pop();
for(int i = 0;i < 4;i++)
{
if(tmp.x + ox[i] > 0&&tmp.x + ox[i] <= n&&tmp.y + oy[i] > 0&&tmp.y + oy[i] <= m&&maps[tmp.x + ox[i]][tmp.y + oy[i]] != '#'&&!vis[tmp.x + ox[i]][tmp.y + oy[i]])
{
vis[tmp.x + ox[i]][tmp.y + oy[i]] = 1;
if(num[tmp.x + ox[i]][tmp.y + oy[i]]&&dis[a][num[tmp.x + ox[i]][tmp.y + oy[i]]] > tmp.dis + 1)
dis[a][num[tmp.x + ox[i]][tmp.y + oy[i]]] = tmp.dis + 1;
struct node tt;
tt.x = tmp.x + ox[i];
tt.y = tmp.y + oy[i];
tt.dis = tmp.dis + 1;
q.push(tt);
}
}
}
return;
}
int main()
{
int a, b;
while(~scanf("%d%d%*c", &n, &m)&&(n||m))
{
nn = 1;
mem(num, 0);
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
scanf("%c", &maps[i][j]);
if(maps[i][j] == '@')
nd[nn].x = i, nd[nn].y = j, num[i][j] = nn++;
}
scanf("%*c");
}
scanf("%d", &k);
for(int i = 0;i < k;i++)
scanf("%d%d", &a, &b), nd[nn].x = a, nd[nn].y = b, num[a][b] = nn++;
for(int i = 0;i < (1 << (nn - 1));i++)
for(int j = 0;j < nn;j++)
dp[i][j] = inf;
for(int i = 0;i < nn;i++)
for(int j = 0;j < nn;j++)
dis[i][j] = inf;
for(int i = 1;i < nn;i++)
bfs(i);
dp[1][1] = 0;
for(int i = 0;i < (1 << (nn - 1));i++)
{
for(int j = 1;j < nn;j++)
{
if(i&(1 << (j - 1))&&dp[i][j] != inf)
{
for(int k = 1;k < nn;k++)
{
if(!(i&(1 << (k - 1))))
dp[i + (1 << (k - 1))][k] = min(dp[i + (1 << (k - 1))][k], dp[i][j] + dis[j][k]);
}
}
}
}
int ans = inf;
for(int i = 1;i < nn;i++)
ans = min(ans, dp[(1 << (nn - 1)) - 1][i]);
if(ans == inf)
printf("-1\n");
else
printf("%d\n", ans);
}
return 0;
}