传送门:poj2688
题意:从求从给定点出发,遍历所有标记出来的点的最短路。
这题思维很巧妙啊,因为有多个标记点,所以先用bfs求出任意两个标记点以及起始点和任意标记点之间的最短路径,这样就变成了变种的TSP(旅行商)问题,即求遍历所有点的最短路,这时再用dfs求解就行了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define inf 0x3f3f3f3f
char map[22][22];
int book[22][22],dis[22][22];
int vis[15];
int s;
int n,m,num=0,ans=inf;
struct node{
int r,c,time;
}q[500],start,end;
int go[4][2]={0,1,1,0,0,-1,-1,0};
int bfs()
{
memset(book,0,sizeof(book));
queue<node> Q;
node a,t;
Q.push(start);
book[start.r][start.c]=1;
while(!Q.empty())
{
a=Q.front();
Q.pop();
for(int i=0;i<4;i++)
{
t=a;
t.r+=go[i][0];
t.c+=go[i][1];
t.time++;
if(!book[t.r][t.c]&&t.r>=0&&t.c>=0&&t.r<n&&t.c<m&&map[t.r][t.c]!='x')
{ if(t.r==end.r&&t.c==end.c)
{
return t.time;
}
book[t.r][t.c]=1;
Q.push(t);
}
}
}
return inf;
}
void dfs(int pre,int x,int step)
{ if(x==num)
{
ans=min(ans,step);
return ;
}
if(step>ans)
return ;
for(int i=0;i<num;i++)
{
if(dis[pre][i]<inf&&!vis[i])
{
vis[i]=1;
dfs(i,x+1,step+dis[pre][i]);
vis[i]=0;
}
}
return ;
}
int main()
{
while(scanf("%d%d",&m,&n)&&n+m)
{
getchar();
//memset(book,0,sizeof(book));
s=0;
num=0;
ans=inf;
int flag=0;
for(int i=0;i<n;i++)
{
gets(map[i]);
for(int j=0;j<m;j++)
{
if(map[i][j]=='*'||map[i][j]=='o')//将每个标记点保存
{
q[num].r=i;
q[num].c=j;
q[num].time=0;
if(map[i][j]=='o')
{
s=num;
}
num++;
}
dis[i][j]=inf;//初始化
}
}
for(int i=0;i<num;i++)
for(int j=i+1;j<num;j++)
{
start=q[i];
end=q[j];
dis[i][j]=dis[j][i]=bfs();//求任意两点间最短路
if(dis[i][j]==inf)
{
flag=1;
break;
}
}
if(flag)
{
printf("-1\n");
continue;
}
memset(vis,0,sizeof(vis));
vis[s]=1;
dfs(s,1,0);//从起始点开始搜索
printf("%d\n",ans);
}
return 0;
}