题目大意:给定一张图,包括 ' . ' ' * ' ' o ' ' x ',分别为可行点,目标(可能不止一个),墙;
目标:以最短的距离遍历这个图上的所有 * ,机器人可以直接清理垃圾无需时间;
地图大概长这样:
. . . . . . .
.o. . .*. .
. . . x . . .
.* . . . * .
. . . . . . . ( hmmm 意会。。
.o. . .*. .
. . . x . . .
.* . . . * .
. . . . . . . ( hmmm 意会。。
发现,这不就是一个BFS走地图吗?
so很直接的思路:直接搜,but,状态数巨大,瞬间爆空间,而且基本都是浪费;
再细细一想,我们人扫地不就是直接去扫吗?并不需要向其他方向试一下再扫,于是简化一些步数:我们直接找从 o 到各目标的最近路径,和 各目标之间的最近路径, 因为答案一定存在于这些路上的某几条;
再细细一想,我们人扫地不就是直接去扫吗?并不需要向其他方向试一下再扫,于是简化一些步数:我们直接找从 o 到各目标的最近路径,和 各目标之间的最近路径, 因为答案一定存在于这些路上的某几条;
(好好想一下,在以后的分层图问题中也会遇到相似的情况:找出公共的或必然为答案的路径以减少状态)
这么看来,我们把一个几乎于(我都数不清的)状态数剪到了只有 n+n-1+n-2+..+2+1条路径,于是又可以想到,那排列组合一下?,并不行,虽然对,但是同一开始的BFS,数量爆炸,为总路径的阶乘数,或者,点的阶乘,但是本题给了范围,n<=12,所以勉强接受;
这么看来,我们把一个几乎于(我都数不清的)状态数剪到了只有 n+n-1+n-2+..+2+1条路径,于是又可以想到,那排列组合一下?,并不行,虽然对,但是同一开始的BFS,数量爆炸,为总路径的阶乘数,或者,点的阶乘,但是本题给了范围,n<=12,所以勉强接受;
那现在说一下TSP,(这道题其实是TSP的简化,但是思想是一样的)
其实呢 TSP就是从起点开始,试图遍历所有点一次且仅一次,并且回到原点;
不过这道题不一样的是不要求再回去,所以,只需要半个TSP就好,或者叫 哈密尔顿路?
TSP问题至今没有什么完美的解法,在各大领域都是个未解决问题,so,这里也只能,,直接dfs了,和排列组合没什么区别,就是好写,排列组合还得hash判重;
下面代码里的dfs就是 半个假TSP;在此%%%这么写TSP的大佬(其实我一开始是排列组合来着,然后跪了。。
其实就是遍历每个点的最短花费啦,除了dfs还有一些奇奇怪怪的写法,反正图都建好了;
其实就是遍历每个点的最短花费啦,除了dfs还有一些奇奇怪怪的写法,反正图都建好了;
有想法的可以评论下,本蒟蒻可以学学大佬们XD
emm注意,TSP总是在一张完全图上跑的;因为,,,要涵盖所有可能答案嘛 : )
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
#define M 100000
#define N 1000
#define INF 0x3f3f3f3f
int n,m,vis[N][N],vis1[N],Min;
char maps[N][N];
int k=1,flag=1,dis[N][N];
int dx[4]={0,0,1,-1};int dy[4]={1,-1,0,0};
struct node {
int x,y,step;
}st,end,NOD[M];
bool valid(int x,int y){
return x>=1&&x<=n&&y>=1&&y<=m;
}
int BFS(node st,node end){
node now,nxt;memset(vis,0,sizeof(vis));
queue<node>q;vis[st.x][st.y]=1;q.push(st);
while(q.size()){
now=q.front();q.pop();
for(int i=0;i<4;i++){
nxt.x=now.x+dx[i];
nxt.y=now.y+dy[i];
nxt.step=now.step+1;
if(valid(nxt.x,nxt.y)&&maps[nxt.x][nxt.y]!='x'){
if(!vis[nxt.x][nxt.y]){
if(nxt.x==end.x&&nxt.y==end.y){return nxt.step;}
q.push(nxt);vis[nxt.x][nxt.y]=1;
}
}
}
}return INF;
}
int dfs(int x,int sum,int len){
if(len>Min)return 0;
if(sum>=k){Min=min(Min,len);}
for(int i=1;i<=k;i++){
if(dis[x][i]!=INF&&!vis1[i]){
vis1[i]=1;
dfs(i,sum+1,len+dis[x][i]);
vis1[i]=0;
}
}
}
int main(){
while(scanf("%d%d",&m,&n)){
if(n==m&&n==0)return 0;
memset(dis,0,sizeof(dis));
memset(NOD,0,sizeof(NOD));
memset(vis,0,sizeof(vis));
memset(vis,0,sizeof(vis1));flag=1,k=1;
for(int i=1;i<=n;i++){scanf("%s",maps[i]+1);}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(maps[i][j]=='o'){st.x=i;st.y=j;st.step=0;NOD[1]=st;}
else if(maps[i][j]=='*'){
end.x=i;end.y=j;end.step=0;NOD[++k]=end;
}
}
}
if(k==0){puts("0");continue;}
for(int i=1;i<=k&&flag;i++){
for(int j=i+1;j<=k;j++){
int tmp=BFS(NOD[i],NOD[j]);
if(tmp==INF){flag=0;break;}
dis[i][j]=dis[j][i]=tmp;
}
}if(!flag){puts("-1");continue;}
memset(vis1,0,sizeof(vis1));
Min=INF;
vis1[0]=1;
dfs(1,0,0);printf("%d\n",Min);
}return 0;
}