HDU 5094 題解(狀壓BFS)

題面:

Maze

題目中文大意:
這個故事發生在“星際迷航”的背景下。

“星際爭霸”的副隊長史波剋落入克林貢的詭計中,被關押在他們的母親星球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

分析:

此題應使用廣度優先搜索(BFS)
狀態壓縮:有10種鑰匙,那麼我們用10位二進制來存儲鑰匙串(即一個int整型變量),第i-1位是1表示有第i種鑰匙,爲0則沒有鑰匙
用位運算來判斷是否能通過門(這些操作很常用,應牢記

  1. 將第i種鑰匙加入鑰匙串key
    代碼:key|=(1<<(i-1))
    例:key=0010 ,i=4,1<<(i-1)=1000,0010|1000=1010

  2. 拿着鑰匙串key,是否能通過第i種門
    代碼:if(key&(1<<(i-1)==0) continue
    例:(沒拿到第5種鑰匙,想通過第5種門)key=01101,i=5,1<<(i-1)=10000,00101|10000=0,通不過,continue
    (拿到第4種鑰匙,想通過第4種門)key=01101,i=4,1<<(i-1)=01000,00101|10000=01000,可通過

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 56
#define maxqu 50*50*(1<<11)+10
using namespace std;
int n,m,p,k,s;
struct node{
    int x;
    int y;
    int step;
    int key;//存儲鑰匙 
};
node now,nex;
node queue[maxqu];
int door[maxn][maxn][maxn][maxn];//鄰接矩陣存門
int keys[maxn][maxn];//二維數組存儲每一個點的鑰匙
int used[maxn][maxn][2055];//標誌是否走過
const int walkx[4]={1,-1,0,0},walky[4]={0,0,1,-1};
int fread(){//快速輸入
    int x=0;
    char c=getchar();
    int sign=1;
    while(c<'0'||c>'9') {
        if(c=='-') sign=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*sign;
}
bool judge(int x1,int y1,int x2,int y2){
    if(door[now.x][now.y][nex.x][nex.y]==0) return false;//有牆 
    if(x2>=1&&x2<=n&&y2>=1&&y2<=m) return true;
    else return false;
}
int bfs(){  
    int head=0,tail=0;
    int tmp;
    queue[0].x=1;
    queue[0].y=1;
    queue[0].step=0;
    queue[0].key|=keys[1][1];//起點有鑰匙的特判 
    memset(used,0,sizeof(used));    
    used[1][1][queue[0].key]=1;
    do{
        now=queue[head];
        if(now.x==n&&now.y==m) return now.step;
        for(int i=0;i<4;i++){
            nex.x=now.x+walkx[i];
            nex.y=now.y+walky[i];
            nex.key=now.key;
            nex.step=now.step;
            if(judge(now.x,now.y,nex.x,nex.y)){
                if(door[now.x][now.y][nex.x][nex.y]>0){//開門 
                    tmp=door[now.x][now.y][nex.x][nex.y]-1;
                    if((nex.key&(1<<tmp))==0) continue;
                }
                if(keys[nex.x][nex.y]>0){//拿鑰匙 
                    nex.key|=keys[nex.x][nex.y];
                }
                if(used[nex.x][nex.y][nex.key]==1) continue;
                used[nex.x][nex.y][nex.key]=1;
                tail++;
                queue[tail].x=nex.x;
                queue[tail].y=nex.y;
                queue[tail].key=nex.key;
                queue[tail].step=nex.step+1;
            }
        } 
        head++;
    }while(head<=tail);
    return -1;
}
int main(){
   // freopen("data.txt","r",stdin);
    int x1,y1,x2,y2,v;
    while(cin>>n>>m>>p){
        memset(door,-1,sizeof(door));
        memset(keys,0,sizeof(keys));
        k=fread();
        for(int i=1;i<=k;i++){
            x1=fread();
            y1=fread();
            x2=fread();
            y2=fread();
            v=fread();
            door[x1][y1][x2][y2]=v;//>0門,=0牆,-1無 
            door[x2][y2][x1][y1]=v;
        }
        cin>>s;
        for(int i=1;i<=s;i++){
            x1=fread();
            y1=fread();
            v=fread();
            keys[x1][y1]|=(1<<(v-1));//預處理鑰匙,注意一個位置有多個鑰匙的情況 
        }
        cout<<bfs()<<endl;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章