1. 程式人生 > >廣搜狀態壓縮 OpenJudge 百鍊4105

廣搜狀態壓縮 OpenJudge 百鍊4105

拯救公主
總時間限制:
1000ms
記憶體限制:
65536kB

描述

多災多難的公主又被大魔王抓走啦!國王派遣了第一勇士阿福去拯救她。

身為超級厲害的術士,同時也是阿福的好夥伴,你決定祝他一臂之力。你為阿福提供了一張大魔王根據地的地圖,上面標記了阿福和公主所在的位置,以及一些不能夠踏入的禁區。你還貼心地為阿福製造了一些傳送門,通過一個傳送門可以瞬間轉移到任意一個傳送門,當然阿福也可以選擇不通過傳送門瞬移。傳送門的位置也被標記在了地圖上。此外,你還查探到公主所在的地方被設下了結界,需要集齊K種寶石才能開啟。當然,你在地圖上也標記出了不同寶石所在的位置。

你希望阿福能夠帶著公主早日凱旋。於是在阿福出發之前,你還需要為阿福計算出他最快救出公主的時間。

地圖用一個R×C的字元矩陣來表示。字元S表示阿福所在的位置,字元E表示公主所在的位置,字元#表示不能踏入的禁區,字元$表示傳送門,字元.表示該位置安全,數字字元0至4表示了寶石的型別。阿福每次可以從當前的位置走到他上下左右四個方向上的任意一個位置,但不能走出地圖邊界。阿福每走一步需要花費1個單位時間,從一個傳送門到達另一個傳送門不需要花費時間。當阿福走到寶石所在的位置時,就視為得到了該寶石,不需要花費額外時間。

輸入
第一行是一個正整數T(1 <= T <= 10),表示一共有T組資料。
每一組資料的第一行包含了三個用空格分開的正整數R、C(2 <= R, C <= 200)和K,表示地圖是一個R×C的矩陣,而阿福需要集齊K種寶石才能夠開啟拘禁公主的結界。
接下來的R行描述了地圖的具體內容,每一行包含了C個字元。字元含義如題目描述中所述。保證有且僅有一個S和E。$的數量不超過10個。寶石的型別在數字0至4範圍內,即不會超過5種寶石。
輸出
對於每一組資料,輸出阿福救出公主所花費的最少單位時間。若阿福無法救出公主,則輸出“oop!”(只輸出引號裡面的內容,不輸出引號)。每組資料的輸出結果佔一行。
樣例輸入
1
7 8 2
……..
..S..#0.
.##..1..
.0#…..
…1#…
…##E..
…1….
樣例輸出
11

拿這組測試資料分析

7 8 2
……..
..S..#0.
.#$$..1.
.0#…$.
…1#…
..$…..
..E…..

這是一個狀態壓縮問題,儘量把自己的思路寫詳細一點。最主要的部分就是用一個三維陣列dp[tx][ty][tk]代表在阿福(tx,ty)這個點上面拿了幾個寶石tk。例如一開始阿福(2,3)這個點上面沒有寶石所以狀態為dp[2][3][0],但是阿福要前往下一個點,需要判重防止下次到達旁邊的點後又走回來,所以將dp[2][3][0]賦值為1,…….當到達(4,7)時阿福所擁有的寶石仍為0,所以dp[4][7][0]=1,當到達(3,7)這個點時dp[3][7][2]=1, 為什麼是2呢?因為寶石的資訊是不一樣的,是0號寶石,還是1號寶石,還是2號寶石……!所以用二進位制編碼的1111代表擁有0,1,2,3四塊寶石,用1011代表擁有了0,1,3號寶石!然後將其轉換成10進位制數字,這樣就記錄了阿福在每次移動時所攜帶寶石具體資訊(到底是哪幾塊)。在移動到(2,7)位置時狀態轉化為dp[2][7][3], 下次再移動到(3,7)這個位置時其狀態為dp[3][7][3],所以在兩次到達(3,7)的位置時其狀態是不一樣的<所攜帶的寶石是不一樣的>。在具體實現寶石的獲取和判斷時,用 | 運算。因為需要集齊k個寶石(假如給了0,1,2,3 四種寶石但是輸入的k值為2,所以加了一個check()加以判斷)。

程式碼:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<limits>
using namespace std;
#define MAX  201
#define  N   1<<5-1   //不減1  是100000  減之後就是11111--代表5種寶石全都擁有的情況
#define  CS   10
char maps[MAX][MAX];
int dp[MAX][MAX][N];
int R,C,K;
int cuansong[CS][2];  //儲存傳送門的座標
int numofcs=0;//傳送門的數量
int dir[2][4]={{1,0,0,-1},{0,1,-1,0}};
int dignum=0; //整個地圖寶石總數,當需要蒐集的種類大於它時,是個根本不可能完成的任務!
struct node{
    int x;
    int y;
    int step;
    int key;
    node(int xx,int yy,int ss,int kk):x(xx),y(yy),step(ss),key(kk){};
};
bool check(int tk){
    int cnt=0;
    for(int i=0;i<=5;i++){
        if((tk>>i)&1)cnt++;
    }
    if(cnt>=K) return true;
    return false;
}
int BFS(int x,int y){
    queue<node> que;
    dp[x][y][0]=1;
    node temp(x,y,0,0);
    que.push(temp);
    while(!que.empty()){
        temp=que.front();
        que.pop();
        for(int i=0;i<4;i++){     //上下左右四方向
            int tx=temp.x+dir[0][i];
            int ty=temp.y+dir[1][i];
            int tt=temp.step;
            int tk=temp.key;
            if(dp[tx][ty][tk]) continue;
            if(tx<0 || tx>=R  || ty<0  || ty>=C ) continue;
            if(maps[tx][ty]=='#') continue;
            if(maps[tx][ty]=='E'){
                if(check(tk)) return temp.step+1;
            }
            if(isdigit(maps[tx][ty])){    //是數字的情況
                dp[tx][ty][tk]=1;
                tk=tk|(1<<(maps[tx][ty]-'0'));  //  | 運算
                que.push(node(tx,ty,tt+1,tk));
            }
            if(maps[tx][ty]=='.'){
                dp[tx][ty][tk]=1;
                que.push(node(tx,ty,tt+1,tk));
            }
            if(maps[tx][ty]=='$'){
                dp[tx][ty][tk]=1;
                que.push(node(tx,ty,tt+1,tk));
                for(int j=0;j<numofcs;j++){  //將其分佈到每個傳送門去,且不花費時間
                    tx=cuansong[j][0];
                    ty=cuansong[j][1];
                    if(!dp[tx][ty][tk]){
                        dp[tx][ty][tk]=1;
                        que.push(node(tx,ty,tt+1,tk));
                    }
                }
            }
        }
    }
    return -1;
}
int main(){
    int n;
    cin>>n;
    int x,y;
    while(n--){
        numofcs=0;
        dignum=0;
        memset(dp,0,sizeof(dp));
        cin>>R>>C>>K;
        for(int i=0;i<R;i++)
        for(int j=0;j<C;j++){
            cin>>maps[i][j];
            if(maps[i][j]=='S'){
                x=i;
                y=j;
                maps[i][j]='.';
            }
            if(maps[i][j]=='$'){
                cuansong[numofcs][0]=i;
                cuansong[numofcs][1]=j;
                numofcs++;
            }
            if(isdigit(maps[i][j]))
                dignum++;

        }
        if(K>dignum){
            cout<<"oop!"<<endl;
            continue;
        }
        int ans=BFS(x,y);
        if(ans==-1) cout<<"oop!"<<endl;
        else cout<<ans<<endl;
    }
    return 0;
}


相關推薦

狀態壓縮 OpenJudge 4105

拯救公主 總時間限制: 1000ms 記憶體限制: 65536kB 描述 多災多難的公主又被大魔王抓走啦!國王派遣了第一勇士阿福去拯救她。 身為超級厲害的術士,同時也是阿福的好夥伴,你決定祝他一臂之力。你為阿福提供了一張大魔王根據地

hdu1429 勝利大逃亡(續) (+狀態壓縮

#include <iostream> #include <queue> #include <cstring> #include <cstdio> using namespace std; const int maxn = 22; int dir[4][2]

Saving Tang Monk II (+狀態

時間限制:1000ms 單點時限:1000ms 記憶體限制:256MB 描述 《Journey to the West》(also 《Monkey》) is one of the Four Great Classical Novels of Chinese liter

獨輪車(狀態轉移的下一步伐的理解)

Problem D 獨輪車 時限:1000ms 記憶體限制:10000K 總時限:3000ms 描述: 獨輪車的輪子上有紅、黃、藍、白、綠(依順時針序)5種顏色,在一個如下圖所示的20*20的迷宮內每走一個格子,輪子上的顏色變化一次。獨輪車只能向前推或在原地轉向。

OpenJudge習題解答(C++)--題4085:陣列去重排序

題: 總時間限制: 1000ms 記憶體限制: 1000kB 描述 小吉是銀行的會計師,在處理銀行帳目的時候,遇到了一些問題。有一系列整數,其中含有重複的整數,需要去掉重複後,排序輸出,你能幫助小

OpenJudge習題解答(C++ )--題4112:情報破譯-Cryptanalysis

題: 總時間限制:1000ms     記憶體限制:65536kB描述 A國和B國正在進行一場戰爭。A國通過間諜知道B國的情報加密規則為: 1.    僅對字母加密,其他符號保留(如空格,逗號等)

OpenJudge習題解答(C++)--題2690:首字母大寫

題: 總時間限制: 1000ms 記憶體限制: 65536kB 描述對一個字串中的所有單詞,如果單詞的首字母不是大寫字母,則把單詞的首字母變成大寫字母。在字串中,單詞之間通過空白符分隔,空白符包括:

OpenJudge習題解答(C++)--題4072:判斷多個點是否在同一直線

題: 總時間限制: 1000ms 記憶體限制: 65536kB 描述 有N(1<=n<=100)< span="">個互不重合的點,並給出它們的座標(xi,yi),問這些點

OpenJudge-2950-摘花生-C語言

描述: 魯賓遜先生有一隻寵物猴,名叫多多。這天,他們兩個正沿著鄉間小路散步,突然發現路邊的告示牌上貼著一張小小的紙條:“歡迎免費品嚐我種的花生!——熊字”。 魯賓遜先生和多多都很開心,因為花生正是他們

OpenJudge習題解答(C++)--題2704:競賽評分

題: 總時間限制: 1000ms 記憶體限制: 65536kB 描述現舉行一次小競賽,參賽的3支隊伍,編號為1,2,3.每支佇列輪流回答問題,如果回答正確,加10分;回答錯誤,扣10分;放棄回答不得

OpenJudge習題解答(C++)--題4110:聖誕老人的禮物-Santa Clau’s Gifts

題: 總時間限制: 1000ms 記憶體限制: 65536kB 描述 聖誕節來臨了,在城市A中聖誕老人準備分發糖果,現在有多箱不同的糖果,每箱糖果有自己的價值和重量,每箱糖果都可以拆分成任意散裝組

OpenJudge習題解答(C++)--題4045:與3和5無關的數

題: 總時間限制: 1000ms 記憶體限制: 65536kB 描述 一個正整數,如果它能被x整除,或者它的十進位制表示法中某個位數上的數字為x,則稱其為與x相關的數.現求所有小於等於n(n<

OpenJudge習題解答(C++)--題3142:球彈跳高度的計算

題: 總時間限制: 1000ms 記憶體限制: 65536kB 描述 一球從某一高度落下(整數,單位米),每次落地後反跳回原來高度的一半,再落下。 程式設計計算氣球在第10次落地時,共經過多少米?

POJ 1632 Vase collection【狀態壓縮+索】

possible span pro there ini -- cal collector 找到 題目傳送門:http://poj.org/problem?id=1632 Vase collection Time Limit: 1000MS Memory Limi

魔板 Magic Squares(狀態轉化)

整數 展開 fine cstring d+ 康拓 空格 來看 reg 題目背景 在成功地發明了魔方之後,魯比克先生發明了它的二維版本,稱作魔板。這是一張有8個大小相同的格子的魔板: 1 2 3 4 8 7 6 5 題目描述 我們知道魔板的每一個方格都有一種顏色。這

2018度之星資格賽___1001調查問卷——狀態壓縮

補題連結:傳送門 題目大意:   有TTT組樣例,nnn份問卷,每份問卷有mmm個問題,答案由A或B組成(相當於nnn條長度為mmm的01序列),在這mmm個問題中任意選取一部分,要使這新的零散問卷互不相同,且至少有k對,問這樣選取一共有多少種方案??? 解題思

:codevs-3344(初步bfs)

def miss bool ret map efault 變量 -a print                 一道典型的迷宮問題 小剛在迷宮內,他需要從A點出發,按順序經過B,C,D……,到達最後一個點,再回到A點。迷宮內有些障礙,問至少走幾步。 輸入描述 I

水災 1000MS 64MB ()

土豪 else ++ hellip 石頭 cstring clu 自己 cst 水災(sliker.cpp/c/pas) 1000MS 64MB 大雨應經下了幾天雨,卻還是沒有停的樣子。土豪CCY剛從外地賺完1e元回來,知道不久除了自己別墅,其他的地方都將會被洪水淹沒。

HDU 1429--勝利大逃亡(續)【BFS &amp;&amp; 狀態壓縮

sizeof ott 擁有 之間 數據 memset tdi mes mod 勝利大逃亡(續) Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) To

POJ-3984-迷宮問題-BFS()-手寫隊列

org ast href || while div 要去 廣搜 trac 題目鏈接:http://poj.org/problem?id=3984 這個本來是個模板題,可是老師要去不能用STL裏的queue,得自己手寫解決。ORZ....看別人的博客學習。新技能get。。