bfs+位运算 hdu 5094 有钥匙的迷宫

题意:给你一个n*m的矩阵,每个格子可以移动到他上下左右四个格子.现在有些格子之间有门或墙.墙不能通过,每个门需要对应的钥匙打开.最多10种门,钥匙分布在某些格子上,走到这些格子上就能拿到钥匙.现在要从(1,1)走到(n,m)问最少要走多少步.如果不能到达输出-1.

样例解释:

4 49

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

有4*4的矩阵.其中有9个门或者墙:(1,2),(1,3)之间有门2.(1,2),(2,2)间是墙.....有两把钥匙:(2,1)上有钥匙2.(4,2)上有钥匙1.

解法:bfs基础上加 位运算.用一个数字记录当前拥有钥匙的情况.如:0000000011 (3)代表拥有钥匙1和2.然后判断点u到点v是否可以走.

代码:

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int n,m,p;
int g[3000][3000];
int ans=INF;
int dis[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int keylocal[800];
int vis[3000][1050];
struct node
{
    int step,num;
    int keys;
};
struct dian{
    int x,y;
}nod[3000];
bool haskey(int u,int v,node now)
{
    if(g[u][v]==-1){
        return true;
    }
    else{
        int key=now.keys;
        int doors=g[u][v];
        key>>=(doors-1);
        if(!(key & 1)){
            return false;
        }
        return true;
    }
}
void bfs()
{
    memset(vis,0,sizeof(vis));
    queue<node> que;
    node now;
    now.keys=0;
    if(keylocal[1]){
        int s=keylocal[1];
        int count=1;
           while(s){
                if(s&1){
                    int w=now.keys>>(count-1);
                    if(!(w&1)){
                        now.keys=now.keys+(1<<(count-1));
                    }
                }
                s=s>>1;
                count++;
           }
    }
    now.num=1,now.step=0;
    que.push(now);
    while(!que.empty()){
        node now=que.front();
        que.pop();
        int u=now.num;
        if(u==n*m){
            ans=now.step;
            return ;
        }
        for(int i=0;i<4;i++){
            int dx=nod[now.num].x+dis[i][0];
            int dy=nod[now.num].y+dis[i][1];
            int v=(dx-1)*m+dy;
            if(dx>=1 && dx<=n && dy>=1 && dy<=m && g[u][v]!=0 && haskey(u,v,now)&& !vis[v][now.keys]){
                vis[v][now.keys]=1;
                node next;
                next.num=v;
                next.step=now.step+1;
                next.keys=now.keys;
                if(keylocal[v]){
                    int s=keylocal[v];
                    //cout<<"s "<<s<<endl;
                    int count=1;

                   while(s){
                        if((s & 1)){
                            int w=next.keys>>(count-1);
                            if(!(w&1)){
                                    next.keys=next.keys+(1<<(count-1));
                            }
                            //cout<<"key "<<next.keys<<endl;
                            //cout<<"keys "<<s<<endl;
                        }
                        s=s>>1;
                        count++;
                   }
                }
                que.push(next);
            }
        }
    }
}
void make()
{
    int cnt=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            nod[cnt].x=i;
            nod[cnt++].y=j;
        }
    }
    for(int i=1;i<=n*m;i++){
        for(int j=0;j<4;j++){
            int dx=nod[i].x+dis[j][0];
            int dy=nod[i].y+dis[j][1];
            int v=(dx-1)*m+dy;
            if(dx>=1 && dx<=n && dy>=1 && dy<=m){
                g[i][v]=-1;
                g[v][i]=-1;
            }
        }
    }
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&p)){
        ans=INF;
        int k;
        memset(g,0,sizeof(g));
        memset(keylocal,0,sizeof(keylocal));
        scanf("%d",&k);
        make();
        for(int i=0;i<k;i++){
            int x1,y1,x2,y2,w;
            scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&w);
            int u=(x1-1)*m+y1;
            int v=(x2-1)*m+y2;
            if(g[u][v]==-1){
                g[u][v]=w;
            }
            else if(g[u][v]==0){
                g[u][v]=0;
            }
            g[v][u]=g[u][v];
        }
        int key;
        scanf("%d",&key);
        for(int i=0;i<key;i++){
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            int s=keylocal[(x-1)*m+y]>>(w-1);
            if(!(s&1)){
                keylocal[(x-1)*m+y]+=(1<<(w-1));
            }
        }
        bfs();
        if(ans>=INF){
            printf("-1\n");
        }
        else{
            printf("%d\n",ans);
        }
    }
    return 0;
}
时间: 2024-10-07 04:34:55

bfs+位运算 hdu 5094 有钥匙的迷宫的相关文章

POJ 1753 bfs+位运算

T_T ++运算符和+1不一样.(i+1)%4 忘带小括号了.bfs函数是bool 型,忘记返回false时的情况了.噢....debug快哭了...... DESCRIPTION:求最少的步骤.使得棋盘上的棋子全黑或者全白.奇数次相当于1次.偶数次相当于不翻. bfs用来求解最优问题.主要用来求距离初始状态路径最短的路径.思想是暴力枚举+位运算.第一次做位运算的题目..醉醉的啦...... 附代码: #include<stdio.h>#include<string.h>#incl

poj1753-Flip Game BFS+位运算

题目大意:有一个4*4的方格,每个方格中放一粒棋子,这个棋子一面是白色,一面是黑色.游戏规则为每次任选16颗中的一颗,把选中的这颗以及它四周的棋子一并反过来,当所有的棋子都是同一个颜色朝上时,游戏就完成了.现在给定一个初始状态,要求输出能够完成游戏所需翻转的最小次数,如果初始状态已经达到要求输出0.如果不可能完成游戏,输出Impossible. 主要思想: 1.如果用一个4*4的数组存储每一种状态,不但存储空间很大,而且在穷举状态时也不方便记录.因为每一颗棋子都只有两种状态,所以可以用二进制0和

hdu 5094 Maze (BFS+状压)

题意: n*m的迷宫.多多要从(1,1)到达(n,m).每移动一步消耗1秒.有P种钥匙. 有K个门或墙.给出K个信息:x1,y1,x2,y2,gi    含义是(x1,y1)与(x2,y2)之间有gi.gi=0:墙   1,2,3.... :第1种门,第2种门,第3种门..... 有S把钥匙.给出S个信息:x1,y1,qi    含义是位置(x1,y1)上有一把第qi种的钥匙. 问多多最少花多少秒到达(n,m).若无法到达输出-1. 数据范围: (1<= n, m <=50, 0<= p

POJ 1166 The Clocks 位运算与BFS

1.题意:有一组3*3的只有时针的挂钟阵列,每个时钟只有0,3,6,9三种状态:对时针阵列有9种操作,每种操作只对特点的几个时钟拨一次针,即将时针顺时针波动90度,现在试求从初试状态到阵列全部指向0的状态所需要的最小操作数的操作方案: 2.输入输出:输入给出阵列初始状态,0,1,2,3分别表示0,3,6,9:要求输出最快方案的操作序列: 3.分析:IOI 1994的考题,BFS是比较容易想到的方法之一,关键是如何简洁的表示和改变BFS过程中的阵列状态:这里使用位运算的方法:具体如下: 首先一共9

hdu 1882 Strange Billboard(位运算+枚举)

http://acm.hdu.edu.cn/showproblem.php?pid=1882 感觉非常不错的一道题. 给一个n*m(1<=n,m<=16)的矩阵,每一个格子都有黑白两面,当翻一个格子时,它的上下左右都要翻转,问最后使格子全变为白色的最少翻转步数. 仅仅需枚举第一行的状态即可,由于对于第i(i>=2)行j列翻转情况受上一行的制约,仅仅有当上一行也是'X'的时候,该行j列才干翻转,使i-1行j列变为'.',否则i行j列不能翻转.依次进行下去,当最后一行全变为白色,说明翻转成功

HDU 5023 A Corrupt Mayor&#39;s Performance Art(线段树+优美的位运算)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5023 Problem Description Corrupt governors always find ways to get dirty money. Paint something, then sell the worthless painting at a high price to someone who wants to bribe him/her on an auction, this

HDU 2276 Kiki &amp; Little Kiki 2 (位运算+矩阵快速幂)

HDU 2276 Kiki & Little Kiki 2 (位运算+矩阵快速幂) ACM 题目地址:HDU 2276 Kiki & Little Kiki 2 题意: 一排灯,开关状态已知,每过一秒:第i个灯会根据刚才左边的那个灯的开关情况变化,如果左边是开的,它就会变化,如果是关的,就保持原来状态.问m秒后的状态. 第1个的左边是最后一个. 分析: 转移不好想啊... 变化是这样的: 原来 左边 变化 1 1 0 1 0 1 0 1 1 0 0 0 然后想到 (~原来)^(左边)=变化

HDU 1882 Strange Billboard(位运算)

题目链接 题意 : 给你一个矩阵,有黑有白,翻转一个块可以让上下左右都翻转过来,问最少翻转多少次能让矩阵变为全白. 思路 : 我们从第一行开始枚举要翻转的状态,最多可以枚举到2的16次方,因为你只要第一行的确定了,第二行要翻转的也就确定了,所以第一行的状态决定了最后的状态.看了网上大神,真是让位运算废了啊,,,,,太复杂了...... 1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #

Vijos 1206 CoVH之再破难关 BFS与位运算

1.题意:一个由01组成的4*4的矩阵,可以实现相邻元素交换位置的操作,给出初试状态和目标状态,试求最少操作数的方案: 2.输入输出:输入给出初试矩阵和目标矩阵:要求输出最小操作的次数: 3.分析:输出最小操作数,很容易联想到使用BFS,这里为了方便表示,把4*4的矩阵拉成一个16个数的数组来看,并用一个16位二进制数表示其状态:用位运算来实现交换某两位的状态,另外再稍微注意一下如何在表示"相邻"的概念即可: 1 # include <iostream> 2 # inclu