【BFS】新飛行棋
測評地址傳送門
Description
期末考試終於結束了。Andy同學感覺鬆了一口氣,他決定重溫小時候的快樂時光–下飛行棋。但是他弄丟了傳統飛行棋需要的骰子,因此他發明了一種新型的飛行棋遊戲,規則如下:棋盤上有n個格子,由近到遠分別編號為1到n。對於1≤i≤n,第i個格子上寫著一個正整數Ni。當玩家處於第a個格子時,他可以選擇往後走Na步,或者往前倒退Na步。當然如果Na+a>n,那麼他就只能選擇後退;同理如果a−Na<1,那麼他就只能選擇前進。保證不會出現既不能前進又不能後退的格子。
Andy學完程式設計後對一個問題很感興趣:從編號s出發,至少需要經過幾把,可以到達t點?(例如在a點選擇往前走Na步,稱之為一把)。
Input
第一行三個整數,分別為n,s,t意義如題面所述。
第二行n個正整數,第i個數為Ni。
Output
一個數,為最少經過的把數。如果s無法到達t,輸出-1。
Samples
Input Copy
6 6 4
1 2 2 3 1 2
Output
1
Hint
對於前10%的資料,s=t;
對於前40%的資料,n≤200;
對於另外10%的資料,s無法到達t;
對於100%的資料,n≤200000;
Source
石光中學 FCS2018基礎班day 6
多次遇到過這個題了,但之前都沒寫出來,嫌它太麻煩,看了同學寫的部落格,還是感覺迷迷瞪瞪的,今天再次與此題相遇,腦袋中蹦出必須將其解決的想法,再次回去看了同學的部落格,終究不是自己寫的,領悟不到精髓。不過不難解決,換用BFS的思路一發順利將其KO。AC後的感覺,別說,還真棒,哈哈哈哈。
解題思路:
運用常見的BFS思想,將BFS求最短路融合其中,值得注意的一點是,BFS的搜尋方向,無疑,這裡僅有兩個方向供我們搜尋,向前 o r or or 向後,分別判斷向前或向後又沒超出邊界,若在邊界內且向此方向走後的花費最少(即路徑最短),就將此點放入佇列,繼續後面的搜尋,最後依照最短路的方式,輸出目的地到出發地的路徑即可,莫忘判斷不可到達的情況。至此,完結。看程式碼。
上程式碼:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
int a[200010];
int n,s, t;
int ans;
int dist[200010];
void bfs()
{
memset(dist,0x3f,sizeof dist);
queue<PII> q;
q.push({s,a[s]});
dist[s] = 0;
while(q.size())
{
PII tmp = q.front();q.pop();
int idx = tmp.first;
int step = tmp.second;
int j = idx + step;
if(j <= n && dist[j] > dist[idx] + 1)
{
dist[j] = dist[idx] + 1;
q.push({j,a[j]});
}
j = idx - step;
if(j >= 1 && dist[j] > dist[idx] + 1)
{
dist[j] = dist[idx] + 1;
q.push({j,a[j]});
}
}
}
int main()
{
scanf("%d%d%d",&n,&s,&t);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
bfs();
if(dist[t]==0x3f3f3f3f) puts("-1");
else printf("%d\n",dist[t]);
return 0;
}