Maze HDU - 5094(BFS)

在《星际迷航》背景下,Kirk必须穿越充满障碍的迷宫,从Qo'noS救出被囚禁的Spock。通过合理规划路径和收集钥匙,Kirk需在最短时间内完成任务。此问题转化为状态搜索,每个位置结合钥匙集合形成不同状态,采用BFS算法求解。

This story happened on the background of Star Trek.

Spock, the deputy captain of Starship Enterprise, fell into Klingon’s trick and was held as prisoner on their mother planet Qo’noS.

The captain of Enterprise, James T. Kirk, had to fly to Qo’noS to rescue his deputy. Fortunately, he stole a map of the maze where Spock was put in exactly.

The maze is a rectangle, which has n rows vertically and m columns horizontally, in another words, that it is divided into n*m locations. An ordered pair (Row No., Column No.) represents a location in the maze. Kirk moves from current location to next costs 1 second. And he is able to move to next location if and only if:

Next location is adjacent to current Kirk’s location on up or down or left or right(4 directions)
Open door is passable, but locked door is not.
Kirk cannot pass a wall

There are p types of doors which are locked by default. A key is only capable of opening the same type of doors. Kirk has to get the key before opening corresponding doors, which wastes little time.

Initial location of Kirk was (1, 1) while Spock was on location of (n, m). Your task is to help Kirk find Spock as soon as possible.
Input
The input contains many test cases.

Each test case consists of several lines. Three integers are in the first line, which represent n, m and p respectively (1<= n, m <=50, 0<= p <=10).
Only one integer k is listed in the second line, means the sum number of gates and walls, (0<= k <=500).

There are 5 integers in the following k lines, represents x i1, y i1, x i2, y i2, g i; when g i >=1, represents there is a gate of type gi between location (x i1, y i1) and (x i2, y i2); when g i = 0, represents there is a wall between location (x i1, y i1) and (x i2, y i2), ( | x i1 - x i2 | + | y i1 - y i2 |=1, 0<= g i <=p )

Following line is an integer S, represent the total number of keys in maze. (0<= S <=50).

There are three integers in the following S lines, represents x i1, y i1 and q i respectively. That means the key type of q i locates on location (x i1, y i1), (1<= q i<=p).
Output
Output the possible minimal second that Kirk could reach Spock.

If there is no possible plan, output -1.
Sample Input
4 4 9
9
1 2 1 3 2
1 2 2 2 0
2 1 2 2 0
2 1 3 1 0
2 3 3 3 0
2 4 3 4 1
3 2 3 3 0
3 3 4 3 0
4 3 4 4 0
2
2 1 2
4 2 1
Sample Output
14

本质上在同一点不同钥匙的集合构成了多个不同状态,这和我之前有道升降机的题目很像,那就是xyx,y,钥匙集合来构成一个点了,然后做一个bfs就可以了,其实不难的,但是细节很多的。
代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#define maxx 55
using namespace std;

int a[maxx][maxx][maxx][maxx];
int n,m,k,p,s;
int mapp[maxx][maxx];
struct node
{
    int x,y;
    int step;
    int state;
    node(){}
    node(int _x,int _y,int _step,int _state):x(_x),y(_y),step(_step),state(_state){}
};
bool vis[maxx][maxx][1<<11];
int b[][2]={{0,1},{0,-1},{1,0},{-1,0}};
int work()
{
    queue<node> que;
    que.push(node(1,1,0,mapp[1][1]));
    vis[1][1][mapp[1][1]]=1;
    int ans;
    bool sign=true;
    while(que.size()&&sign)
    {
        node temp=que.front();
        que.pop();
        for(int i=0;i<4;i++)
        {
            int xt=temp.x+b[i][0];
            int yt=temp.y+b[i][1];
            if(xt<1||xt>n||yt<1||yt>m)continue;//越界判断
            int h=a[temp.x][temp.y][xt][yt];
            if(!h)continue;//看有没有墙
            if(h!=-1&&(temp.state&(1<<(h-1)))==0) continue;//对于这个门我有没有钥匙
            int newS=temp.state|mapp[xt][yt];//拿到新钥匙(如果有)
            if(vis[xt][yt][newS])continue;//判断有没有之前访问过
            vis[xt][yt][newS]=true;
            if(xt==n&&yt==m)
            {
                sign=false;
                ans=temp.step+1;
                break;
            }//是否到达终点
            que.push(node(xt,yt,temp.step+1,newS));//入队

        }
    }
    if(sign)return -1;
    else return ans;
}
void init()
{
    memset(a,-1,sizeof(a));
    memset(vis,false,sizeof(vis));
    memset(mapp,0,sizeof(mapp));
}
int main()
{
    int x1,y1,x2,y2,g;
    while(scanf("%d%d%d",&n,&m,&p)==3)
    {
        init();
        cin>>k;
        for(int i=0;i<k;i++)
        {
            scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&g);
            a[x1][y1][x2][y2]=g;
            a[x2][y2][x1][y1]=g;
        }
        cin>>s;
        for(int i=0;i<s;i++)
        {
            scanf("%d%d%d",&x1,&y1,&g);
            mapp[x1][y1]|=1<<(g-1);
        }
        cout<<work()<<endl;
    }

    return 0;
}
<think>嗯,用户需要寻找杭电OJ问题1044的解答。首先,我要确认这个问题的具体内容。HDU 1044题目名是“Collect More Jewels”,这是一个经典的BFS(广度优先搜索)与状态压缩结合的题目,可能涉及最短路径和动态规划。 接下来,我应该回忆一下这个问题的结构。通常这类问题是在迷宫中收集宝石,同时有时间或步数限制。需要找到最优路径收集最多的宝石。可能的解决方法是使用BFS遍历所有可能的状态,记录每个位置和已收集宝石的状态,同时跟踪剩余时间。 然后,我需要验证自己的思路是否正确。比如,是否需要用状态压缩来保存宝石的收集情况,每个宝石对应一个二进制位。同时,如何处理多个状态(位置、宝石收集状态、剩余时间)的组合,避免重复访问。可能需要使用三维数组来记录访问状态:x坐标、y坐标、宝石状态。 另外,考虑如何高效地遍历所有可能的路径。BFS适合寻找最短路径,但结合状态压缩后,状态空间会变得很大,需要优化。可能要考虑剪枝策略,比如当剩余时间不足以到达出口时提前终止。 还要注意迷宫中的障碍物、起点、出口的位置,以及宝石的位置。预处理宝石的位置,并为每个宝石分配一个唯一的位标识。同时,可能需要预处理各宝石之间及出口的最短路径,以减少重复计算。 用户可能需要具体的代码实现,所以应该提供一个Python示例,使用BFS和状态压缩。代码结构应包括读取输入、初始化队列和访问数组、处理每一步移动、更新状态,并在到达出口时记录最大宝石数。 在编写代码时,需要注意输入格式,比如迷宫的大小、时间限制、宝石数量。可能还需要处理多组测试用例。此外,输出格式要求当无法收集任何宝石时输出特定内容,否则输出最大价值。 最后,要确保代码正确性,比如边界情况处理,例如起点就是出口,或者没有宝石的情况。同时,提醒用户杭电OJ可能有特定的输入输出要求,比如多组数据输入需要循环处理,或者输出格式的细节。 相关问题部分,应该围绕BFS、状态压缩、动态规划优化、类似题目推荐以及测试用例设计来展开。这样用户可以从多个角度深入理解问题,并扩展相关知识。</think>### HDU OJ 1044 "Collect More Jewels" 解题思路 该问题要求在限定步数内从迷宫的起点到出口,并尽可能收集更多宝石。核心解法是**BFS(广度优先搜索)结合状态压缩技术**,记录移动路径中每个位置和已收集宝石的状态[^1]。 #### 关键步骤 1. **状态表示** 使用三元组 $(x, y, mask)$ 表示状态,其中: - $(x,y)$: 当前位置坐标 - $mask$: 二进制数表示已收集的宝石(例如第$k$位为1表示第$k$个宝石已收集) 2. **BFS遍历** 初始化队列时加入起点状态 $(sx, sy, 0)$(初始未收集宝石),逐层扩展四个移动方向,并更新状态。 3. **剪枝优化** - 维护三维数组 $vis[x][y][mask]$ 记录是否访问过该状态 - 当剩余步数不足以到达出口时提前终止路径 #### 示例代码(Python) ```python from collections import deque def solve(): W, H, L, M = map(int, input().split()) jewels = [int(input()) for _ in range(M)] maze = [input().strip() for _ in range(H)] # 预处理起点、出口、宝石位置 start = end = None gem_pos = {} gem_id = 0 for i in range(H): for j in range(W): if maze[i][j] == '@': start = (i, j) elif maze[i][j] == '<': end = (i, j) elif maze[i][j] == '*': gem_pos[(i,j)] = gem_id gem_id += 1 dirs = [(-1,0),(1,0),(0,-1),(0,1)] vis = [[[False]*(1<<M) for _ in range(W)] for __ in range(H)] q = deque() max_val = 0 q.append( (start[0], start[1], 0, 0) ) vis[start[0]][start[1]][0] = True while q: x, y, mask, steps = q.popleft() if (x, y) == end: current_val = sum( (mask>>i)&1 * jewels[i] for i in range(M) ) max_val = max(max_val, current_val) continue if steps >= L: continue for dx, dy in dirs: nx, ny = x+dx, y+dy if 0<=nx<H and 0<=ny<W: cell = maze[nx][ny] if cell == '#': continue new_mask = mask if cell == '*' and (nx,ny) in gem_pos: gem = gem_pos[(nx,ny)] new_mask = mask | (1<<gem) if not vis[nx][ny][new_mask]: vis[nx][ny][new_mask] = True q.append( (nx, ny, new_mask, steps+1) ) print(f"Maximum jewels collected: {max_val}" if max_val > 0 else "No solution") solve() ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值