·為了分析方便,可以先做乙個題目簡化。去掉「鑰匙」這個條件,那麼就是乙個bfs或者spfa……現在加上該條件。如本題只給出最多兩種鑰匙,當然你可以繼續堅持bfs等方式,時間不會太差。但是一旦鑰匙種類上公升至15的時候,就有太多情況需要處理(光說你寫bfs的if就是很長的過程,但個人認為時間複雜度依舊能過這道題)。
·如圖是簡化版本的決策方式(為與後文呼應,用spfa):
大方塊是整個地圖。小方塊是乙個房間。那麼你可以在向四個方向走,前提是有路可走(沒有牆)。你本可以輕鬆拯救大兵瑞恩,然後過上幸福快樂的生活,但是你可能在實際問題中遭遇這樣的絕望情況:
明明有路可走,但是那扇門你沒有鑰匙。現在你開始幻想,怎樣才能走過去呢……你妄想:要是在這之前有開這扇門的鑰匙就好了,那我同樣是走相同的路來到這扇門前,但是在那個時空的我就可以輕鬆開門,這個時空的我就只能絕望地去他地尋找鑰匙。
·我們談到了時空斷裂。那麼就乾脆把每個時空也作為狀態的一部分吧!(注意,在這之前你的狀態只有乙個元素,就是當前點座標)。
·由圖可見,你要時空穿梭的條件是你必須具備相應的鑰匙。圖中:如果你在這個房間裡撿到了b,c鑰匙,那麼就有這種穿越方式(藍色有向邊)。由於在這裡「時空」與「座標位置」的地位是相同的【它們無制約關係】。也就是說你穿越兩次時空在向左走一步,和將這些動作反過來,在可行的情況下是等價的。說明這一點的目的在於:這啟示我們,其實這圖中6條邊的意義是相同的。
這樣一來,這道題就變成了普通的最短路問題,只是路多了些,判斷條件多了些。所以可以用二維狀態來表示當前情況,最終答案在每個時空裡找乙個最優的即可(沒喊你把所有鑰匙拿完啊!)。
1#include2【大公尺餅**】#define go(i,a,b) for(int i=a;i<=b;i++)
3#define fo(i,a,x) for(int i=a[x];i>-1;i=e[i].next)
4#define mem(a,b) memset(a,b,sizeof(a))
5#define p 3000
6#define inf 0x3f3f3f3f
7using
namespace std;const
int n=203
;8int dx[4]=,dy[4]=;
9int n,m,p,f,s[n][n],id[n][n],key[n],head[n],k=0
,s,t,dis[p][n];10struct ee[n*n*4];bool
inq[p][n];11void add(int u,int v,int rar);head[u]=k++
;}12struct g;
13int
spfa()14
);17while(!
q.empty())18
);33
}34
}35
}36
}37int ret=inf;go(i,1,p-1)ret=
min(ret,dis[i][t]);38if(ret==inf)ret=-1;return
ret;39
}4041
int
main()42
5152 go(i,1,n)go(j,1 ,m)53
59 }60 scanf("
%d",&
f);61 go(i,1,f)scanf("
%d%d%d
",&a,&b,&c),key[id[a][b]]|=(1
<<
c);62 printf("
%d\n
"
,spfa());63return
0
;64 }
到達同乙個地點時,手上的鑰匙越多越好,不要害怕。
比起那些政客的謊言,我們要聖潔得多。
191 煎餅排序
題目描述 給定陣列 a,我們可以對其進行煎餅翻 我們選擇一些正整數 k a.length,然後反轉 a 的前 k 個元素的順序。我們要執行零次或多次煎餅翻轉 按順序一次接一次地進行 以完成對陣列 a 的排序。返回能使 a 排序的煎餅翻轉操作所對應的 k 值序列。任何將陣列排序且翻轉次數在 10 a....
LeetCode191 統計詞頻
寫乙個 bash 指令碼以統計乙個文字檔案 words.txt 中每個單詞出現的頻率。為了簡單起見,你可以假設 words.txt只包括小寫字母和 每個單詞只由小寫字母組成。單詞間由乙個或多個空格字元分隔。示例 假設 words.txt 內容如下 dayis sunny the thethe sun...
第191場周賽
class solution return res 這裡有個注意的點,maxh maxw這兩個int的值的乘積會超過int的範圍,所以要先轉換為double class solution maxh maxh h horizontalcuts hcut 1 maxh h horizontalcuts ...