HDU4771(2013 Asia Hangzhou Regional Contest )

http://acm.hdu.edu.cn/showproblem.php?pid=4771

题目大意:

给你一幅图(N*M)“@”是起点,"#"是墙,“.”是路,然后图上有K个珠宝,

问是否能全部取走珠宝,若能则输出最小步数,否则-1。

思路,可以bfs处理珠宝与珠宝,珠宝与起点的距离同时还可以判断是否可达,

最后因为K<=4,所以枚举路径输出最小ans

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
using namespace std;
#define N 102
#define inf 0x3f3f3f3f

int n,m,sx,sy,k;
char pic[102][102];
int vis[102][102];
int dis[5][5],d_cnt;    //d_cnt最后有几个点(包括起点)
struct COORD{
    int x,y;
}coord[5];
int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};

int bfs(int &x,int &y){
    memset(vis,0,sizeof(vis));
    queue<int>q;
    q.push(coord[x].x);q.push(coord[x].y);
    int x1,y1,xx,yy,i;
    while(!q.empty()){
        x1=q.front(); q.pop();
        y1=q.front(); q.pop();
        if(x1==coord[y].x&&y1==coord[y].y) return vis[x1][y1];
        for(i=0; i<4; ++i){
            xx=x1+dir[i][0];
            yy=y1+dir[i][1];
            if(xx>0&&xx<=n&&yy>0&&yy<=m&&pic[xx][yy]!='#'&&!vis[xx][yy]){
                vis[xx][yy]=vis[x1][y1]+1;
                q.push(xx); q.push(yy);
            }
        }
    }
    return 0;
}

int main(){
    int i,j,x,y;
    while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){
        for(i=1; i<=n; ++i)
            for(j=1; j<=m; ++j){
                scanf(" %c",&pic[i][j]);
                if(pic[i][j]=='@') sx=i,sy=j;
            }
        scanf("%d",&k);
        d_cnt=1;
        coord[0].x=sx;
        coord[0].y=sy;
        for(i=0; i<k; ++i){
            scanf("%d%d",&x,&y);
            if(x!=sx||y!=sy){   //判断起点上是否放有珠宝
                pic[x][y]='*';
                coord[d_cnt].x=x;
                coord[d_cnt++].y=y;
            }
        }
        int flag=1; //求距离顺便判断是否可到达
        for(i=0; i<d_cnt&&flag; ++i)
            for(j=i+1; j<d_cnt&&flag; ++j){
                flag=bfs(i,j);
                dis[i][j]=dis[j][i]=flag;
            }
        if(!flag) puts("-1");
        else{
            int p[6],ans=inf;
            for(i=0; i<d_cnt; ++i) p[i]=i;
            do{
                int sum=0;
                for(i=0; i<d_cnt-1; ++i)
                    sum+=dis[p[i]][p[i+1]];
                ans=min(ans,sum);
            }while(next_permutation(p,p+d_cnt)&&!p[0]); //全排列枚举
            printf("%d
",ans);
        }
    }
    return 0;
}

然后还有一个问题希望神牛们能解决:要是K加大到50怎么办?

原文地址:https://www.cnblogs.com/Kurokey/p/5276572.html