Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 28651 Accepted Submission(s): 7845
Problem Description
Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.
- Walking: FJ can move from any point
X
to the pointsX - 1
orX + 1
in a single minute - Teleporting: FJ can move from any point
X
to the point2 × X
in a single minute.
If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?
Input
Line 1: Two space-separated integers: N and K
Output
Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.
Sample Input
5 17
Sample Output
4
Hint
The fastest way for Farmer John to reach the fugitive cow is to move along the following path:5-10-9-18-17
, which takes 4 minutes
題意:一頭牛逃跑了,跑到了處,牛不會動。人從處追這頭牛,在一條數軸上行走。人可以移動到,和處,每次移動消耗一分鐘。要求最少的追到牛的時間。
思路:在我看來,這道題用來做BFS入門很合適,與之前做過的“Red And Black”相比,這個可以說是一維的,是一個一維的遍歷。然後有三種情況,分別是前進一步,後退一步,前進二倍的步數。因此也可以說是在遍歷一個三叉樹
。由於是無權最短路,因此用BFS是最合適的。
以題目的示例爲例:
注意:
- 第一點,這裏不會只輸入一個,HDU一向都是在一個程序中測試多個用例,我一開始沒注意到;
- 由於每個結點擴展出三個結點,因此遍歷的複雜度飛速上升;我們必須用邊界剪去一些“樹枝”,不然會超過空間。
剪枝:
- 擴展時,用一個數組記錄,不能擴展出已經走過的節點,即不能回退,以免陷入無效的重複擴展和可能的循環;
- 如果輸入的,那麼只有往後走一條路,因此只需要分鐘;
- 如果當前的,才擴展結點;
- 如果當前的,才擴展結點;
- 如果當前的,才擴展結點。
最終,我們最多隻會擴展出左右個結點,大大降低了複雜度。
代碼如下:
這裏我沒有使用傳統的BFS寫法,使用一個包裹一個表示層數的變量,而是每次直接一個循環將下一層可擴展的結點壓入隊列中。因此找到牛的時候需要一次性跳出兩重循環,所以用了,不用也可以,不過多寫幾句。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100100;
bool vis[maxn] = {false};
int main() {
int n, k;
queue<int> q;
while (~scanf("%d %d", &n, &k)) {
if (n > k) {
printf("%d\n", n - k);
continue;
}
int num = -1;
memset(vis, 0, sizeof(vis));
q.push(n);
vis[n] = true;
while (!q.empty()) {
int size = q.size();
++num;
for (int i = 0; i < size; ++i) {
int v = q.front(); q.pop();
if (v == k) {
printf("%d\n", num);
goto end;
}
if (v - 1 >= 0 && !vis[v - 1]) q.push(v - 1), vis[v - 1] = true;
if (v + 1 <= 100000 && !vis[v + 1]) q.push(v + 1), vis[v + 1] = true;
if (v != 0 && 2 * v <= 100000 && !vis[2 * v]) q.push(2 * v), vis[2 * v] = true;
}
}
end:
while (!q.empty()) q.pop();
}
return 0;
}