找宝箱 (bfs)

Problem Description

作为一个强迫症患者,小 Y 在走游戏里的迷宫时一定要把所有的宝箱收集齐才肯罢休。现在给你一个 N *M 的迷宫,里面有障碍、空地和宝箱,小 Y 在某个起始点,每一步小 Y 可以往上下左右走,当然前提时没有走出迷宫并且走到的点不是障碍。如果小 Y 走到了某个为宝箱的点,那么这个宝箱就被他收集到了,然后此处变为空地。 现在你需要计算小 Y 最少需要走多少步才能收集齐所有的宝箱。

Input

输入包含多组数据。 对于每组数据,第一行两个正整数 N;M(1<=N;M<=100),表示迷宫大小。 接下来 N 行,每行 M 个整数,第 i + 1 行的第 j 个整数表示迷宫第 i 行第 j 列的情况,0 表示空地,-1表示障碍,1 表示宝箱,2 表示小Y 的起始点。保证2 只有一个,且宝箱数量不超过5 个。 数据以两个0 表示结尾。

Output

对于每组数据输出一行,包含一个整数,表示小 Y 最少的步数。如果小 Y 无法收集齐所有宝箱,输出-1。

Sample Input

3 5
1 -1 1 -1 2
0 -1 0 -1 0
0 0 0 0 0
0 0

很久之前遇到的题现在又偶然遇到了,当初一直没看懂,现在终于懂了,不过找不到出处在哪了。

因为要收集完所有宝箱,把起点也作为宝箱,然后求出所有宝箱的两两距离,最后枚举所有 的情况求出最小值.

枚举的时候借用了全排列,方法很巧妙。

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<queue>
#include<algorithm>
using namespace std;
const int M=205;
int n,m;
int map[M][M]; //迷宫
struct point
{
    int r;
    int l;
} p[7];  //记录宝箱位置和初始位置
int run[4][2]= {1,0,-1,0,0,1,0,-1}; //bfs的方向数组
int bfs(point x,point y)   //求两个宝箱的最短距离
{
    int r,l,i,now,next,a[M][M]= {0},mp[M][M];
    queue<int> qu;
    now=x.r*m+x.l;
    qu.push(now);
    for(i=0; i<n; i++) //因为要调用计算多次,所以map不能改变,每次用map 初始mp
        for(l=0; l<m; l++)
            mp[i][l]=map[i][l];
    while(!qu.empty())
    {
        now=qu.front();
        qu.pop();
        for(i=0; i<4; i++)
        {
            r=now/m+run[i][0];
            l=now%m+run[i][1];
            next=r*m+l;
            if(r>=0 &&r<n && l>=0 && l<m && mp[r][l]!=-1)
            {
                a[r][l]+=a[now/m][now%m]+1;
                qu.push(next);
                mp[r][l]=-1;
                if(r==y.r && l==y.l)
                    return a[r][l];
            }
        }
    }
    return -1; //不通时返回
}
int main()
{
    freopen("a.txt","r",stdin);
    int i,j,num,min,dis[M][M];//dis数组保存第i个宝箱到第j个宝箱的最短距离
    while(scanf("%d%d",&n,&m)!=EOF && n!=0 && m!=0)
    {
        memset(dis,0,sizeof(dis));
        int flag=0;//若有宝箱不能到达的标志
        min=10000000;
        num=1;
        for(i=0; i<n; i++)
            for(j=0; j<m; j++)
            {
                cin>>map[i][j];
                if(map[i][j]==2)
                {
                    p[0].r=i;
                    p[0].l=j;
                }
                if(map[i][j]==1  )
                {
                    p[num].r=i;
                    p[num++].l=j;
                }
            }
        for(i=0; i<num; i++)
        {
            for(j=0; j<num; j++)
                if(i!=j)
                {
                    dis[i][j]=bfs(p[i],p[j]);
                    if(dis[i][j]==-1)
                    {
                        flag=1;
                        break;
                    }
                }
            if(flag)
                break;
        }
        if(flag)
        {
            printf("-1\n");
            continue;
        }
        char a[7]= {"012345"};
        //因为最多有5个宝箱,用这个字符串代表排列的顺序,看下面会懂的,有点妙!
        do
        {
            int s=0;
            for(i=0; i<num-1; i++)
            {
                s+=dis[a[i]-‘0‘][a[i+1]-‘0‘];
            }
            if(min>s)  //判断每种情况,
                min=s;
        }
        while(next_permutation(a+1,a+num));
        //一个库函数 第一次经过他之后a[6]={"02354"}
        printf("%d\n",min);
    }
    return 0;
}
时间: 2024-12-16 06:29:15

找宝箱 (bfs)的相关文章

【CodeForces - 598D】Igor In the Museum(bfs)

Igor In the Museum Descriptions 给你一个n*m的方格图表示一个博物馆的分布图.每个方格上用'*'表示墙,用'.'表示空位.每一个空格和相邻的墙之间都有一幅画.(相邻指的是上下左右相邻).你可以从一个空格的位置走到相邻的空格位置.现在你给你若干个(xi,yi)形式的询问,表示你现在在(xi,yi)这个位置(保证为空位)出发,问你从这个点出发你能看到多少幅画. Input 第一行有3个整数n,m,k(3<=n,m<=1000,1<=k<=min(m*m,

bzoj 1064

题意:戳这里 思路:很明显是一个图论模型.. 就两种图形: 1.图中存在环,那么就是所有环的gcd为最大答案.gcd的大于3的最小约数为最小答案 2.不存在环,那么是每个弱连通块的最长链之和为最大答案,最小答案为3.. 但是这一题最关键的是实现,实现技巧太赞了.. 首先,我们可以把每条有向边(u, v)拆成(u, v, 1), (v,  u, -1) 那么对于第二情况,对于每一个联通块直接随便找一个bfs,然后最长链就是maxdist-mindist+1 对于第一种情况,可能出现环套环的情况,这

圣诞福利到!51Testing邀你一起来狂欢!有礼就是任性~(≧▽≦)/~

“我想变成一棵树,一棵只为你存在的圣诞树,顶上最大最亮的那颗星是我的真心,下面挂满我对你的祝福. 你的关注是我的幸福,你的肯定是我的力量,而我将用更多精彩的内容,用心的分享,给你下一个一整年的 精彩!”                                                                                                  ——51Testing软件测试网 圣诞.元旦双节到,为回报小伙伴一直以来的关注与支持,51Testin

NOIP 2009 最优贸易

题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路,双向通行的道路在统计条数时也计为 1 条. C 国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价 格不一定相同.但是,同一种商品在同一个城市的买入价和卖出价始终是相同的. 商人阿龙来到 C 国旅游.当他得知同一种商品在不同城市的价格可能会不同这一信息 之后,便决定在旅游的

Class热替换与卸载

概述 名词解释:所谓热部署,就是在应用正在运行的时候升级软件,却不需要重新启动应用.本文主要是分析Tomcat中关于热部署和JSP更新替换的原理,在此之前先介绍class的热替换和class的卸载的原理. Class热替换 ClassLoader中重要方法: loadClass:ClassLoader.loadClass(…) 是ClassLoader的入口点.当一个类没有指明用什么加载器加载的时候,JVM默认采用AppClassLoader加载器加载没有加载过的class,调用的方法的入口就是

PostgreSQL中查找最大连续性字段

一.建表 lihao=#create table tb (id int,pid int,name varchar); lihao=#INSERT INTO tb VALUES (1, 0, '广东省'); lihao=#INSERT INTO tb VALUES (2, 0, '浙江省'); lihao=#INSERT INTO tb VALUES (3, 2, '衢州市'); lihao=#INSERT INTO tb VALUES (4, 2, '杭州市'); lihao=#INSERT I

Java对List对象进行排序

有时候需要对List对象进行排序,如果每一处都去写一个排序方法,就会产生重复代码的坏味道,而且每一处都写,工作量会很大.我们知道,Java提供了一个Collections.sort()方法可以对List排序,利用Java反射机制,很容易就能写出一个通用的排序方法. 为了防止出现不按照getter,setter规范命名的POJO类,我不打算动态调用getXXX()方法,而是直接获取对象的属性值.为了达到不论是否是public成员变量,都能获取到的目的,在获取到Field后,调用了setAccess

心若迅雷会员账号获取器

心若迅雷会员账号获取器是一个绿色免费的迅雷会员获取小工具,每天都会发布多个有效的迅雷会员账号供大家使用,用户可以使用这些账号登陆迅雷进行离线下载. 获取迅雷白金会员一人一号说明以及流程:点击下面的(立即获取白金会员一人一号)进行获取,会自动打开一个软件安装提示,点击(立即点击安装)然后点软件上的注册账号然后通过注册的账号登陆视频聊天软件,然后随便进个房间免费观看2分钟视频,2分钟以后软件自动发送一人一号白金账号到你邮箱!如果按操作后没发送到自己邮箱请联系客服QQ:1625223157领取一人一号

hihocoder#1050 : 树中的最长路(树中最长路算法 两次BFS找根节点求最长+BFS标记路径长度+bfs不容易超时,用dfs做TLE了)

#1050 : 树中的最长路 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上回说到,小Ho得到了一棵二叉树玩具,这个玩具是由小球和木棍连接起来的,而在拆拼它的过程中,小Ho发现他不仅仅可以拼凑成一棵二叉树!还可以拼凑成一棵多叉树——好吧,其实就是更为平常的树而已. 但是不管怎么说,小Ho喜爱的玩具又升级换代了,于是他更加爱不释手(其实说起来小球和木棍有什么好玩的是吧= =).小Ho手中的这棵玩具树现在由N个小球和N-1根木棍拼凑而成,这N个小球都被小Ho标上了不