Maze HDU - 5094

这个故事发生在“星际迷航”的背景下。 

“星际争霸”的副队长史波克落入克林贡的诡计中,被关押在他们的母亲星球Qo'noS上。 

企业的上尉詹姆斯·T·柯克(James T. Kirk)不得不乘宇宙飞船去救他的副手。幸运的是,他偷走了史波克所在的迷宫地图。 

迷宫是一个矩形,它有n行垂直和m列水平,换句话说,它被分为n * m个位置。有序对(行号,列号)表示迷宫中的位置。柯克从当前位置移动到下一个花费1秒。而且他只有在以下情况下才能移动到下一个位置: 

下一个位置与当前柯克的位置相邻(上下或左右)(4个方向) 
开着的门是可以通行的,但锁着的门不是。 
柯克不能通过一堵墙 

有几种门是默认锁定的。钥匙只能打开相同类型的门。柯克必须在打开相应的门之前拿到钥匙,这样很浪费时间。 

柯克的初始位置是(1,1),而史波克位于(n,m)的位置。你的任务是帮助Kirk尽快找到史波克。

Input

输入包含很多测试用例。 

每个测试用例由几行组成。第一行中有三个整数,分别代表n,m和p (1<= n, m <=50, 0<= p <=10). 
第二行只列出一个整数k,表示门和墙的总数(0<= k <=500). 

在下面的k行中有5个整数,表示 i1, y i1, x i2, y i2, g i; 当g i >=1,表示在位置 (x i1, y i1) 和 (x i2, y i2)之间存在类型gi的门;当g i = 0, 之间存在一个墙(x i1, y i1)和 (x i2, y i2), ( | x i1 - x i2 | + | y i1 - y i2 |=1, 0<= g i <=p ) 

下面的行是一个整数S,表示迷宫中的钥匙的总数。(0<= S <=50). 

在下面的S行中有三个整数,分别表示x i1, y i1和q i这意味着类型为qi的钥匙位于位置 i (x i1, y i1), (1<= q i<=p).

Output

输出Kirk可能达到史波克的可能最小的秒数。 

如果没有可能的计划,输出-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

 

思路:状态压缩dp+bfs

vis[x][y][k]:用来记录走到(x,y)钥匙状态为k是否访问过。这里压缩的就是钥匙的状态。

注意点:

1、若门是通的,那么只要该状态没有被访问过就可以。

2、若门是锁住的,那么必须先有钥匙才可以通过。

 

#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;


int n,m,p,k,x3,y3,x2,y2,g,s,x,y,q;
struct node{
    int x,y,key,cos;
};
int wall[55][55][55][55],keys[55][55],vis[55][55][1<<11];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};

void bfs(){
    queue<node>q;
    vis[1][1][keys[1][1]]=1;
    q.push((node){1,1,keys[1][1],0});
    while(!q.empty()){
        node t=q.front();  q.pop();
        int x=t.x, y=t.y;
        if(x==n&&y==m){
               cout<<t.cos<<endl;
               return;
        }
        for(int i=0; i<4; i++){
            int xx=x+dx[i],yy=y+dy[i];
            if(xx<1||yy<1||xx>n||yy>m||wall[xx][yy][x][y]==0)continue;
            int door=wall[x][y][xx][yy];
            int key=t.key,ke=key|keys[xx][yy];
            //1、假如没有门,并且没有访问过
            //2.有门,且有钥匙开门 ,并且没有访问过
            //两种情况合并如下
            if((((key&(1<<(door-1)))&&door>0)||door==-1)&&vis[xx][yy][ke]==0){
                    vis[xx][yy][ke]=1;
                    q.push((node){xx,yy,ke,t.cos+1});
            }
        }
    }
    cout<<-1<<endl;
}
int main()
{
    while(cin>>n>>m>>p){
       cin>>k;
       memset(wall,-1,sizeof(wall));
       memset(vis,0,sizeof(vis));
       memset(keys,0,sizeof(keys));
       for(int i=1; i<=k; i++){
           cin>>x3>>y3>>x2>>y2>>g;
           wall[x3][y3][x2][y2]=wall[x2][y2][x3][y3]=g;//门可以双向
       }
       cin>>s;
       for(int i=1; i<=s; i++){
          cin>>x>>y>>q;
          keys[x][y]|=1<<(q-1);//可能同一个位置有多吧钥匙
       }
       bfs();
    }
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值