POJ 2688 BFS+TSP 问题

题目大意:给定一张图,包括 ' . ' '  * ' ' o ' ' x ',分别为可行点,目标(可能不止一个),墙;
                 目标:以最短的距离遍历这个图上的所有 * ,机器人可以直接清理垃圾无需时间;
                 地图大概长这样:
                        . . . . . . .
                        .o. . .*. .
                        . . . x . . .
                        .* . . . * .
                        . . . . . . .  ( hmmm 意会。。
发现,这不就是一个BFS走地图吗?
so很直接的思路:直接搜,but,状态数巨大,瞬间爆空间,而且基本都是浪费;
再细细一想,我们人扫地不就是直接去扫吗?并不需要向其他方向试一下再扫,于是简化一些步数:我们直接找从 o 到各目标的最近路径,和 各目标之间的最近路径, 因为答案一定存在于这些路上的某几条;
        (好好想一下,在以后的分层图问题中也会遇到相似的情况:找出公共的或必然为答案的路径以减少状态)
这么看来,我们把一个几乎于(我都数不清的)状态数剪到了只有 n+n-1+n-2+..+2+1条路径,于是又可以想到,那排列组合一下?,并不行,虽然对,但是同一开始的BFS,数量爆炸,为总路径的阶乘数,或者,点的阶乘,但是本题给了范围,n<=12,所以勉强接受;
           那现在说一下TSP,(这道题其实是TSP的简化,但是思想是一样的)
           其实呢 TSP就是从起点开始,试图遍历所有点一次且仅一次,并且回到原点;
           不过这道题不一样的是不要求再回去,所以,只需要半个TSP就好,或者叫 哈密尔顿路?
           TSP问题至今没有什么完美的解法,在各大领域都是个未解决问题,so,这里也只能,,直接dfs了,和排列组合没什么区别,就是好写,排列组合还得hash判重;
           下面代码里的dfs就是 半个假TSP;在此%%%这么写TSP的大佬(其实我一开始是排列组合来着,然后跪了。。
            其实就是遍历每个点的最短花费啦,除了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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值