【BFS】HDU 2717 Catch That Cow

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 points X - 1 or X + 1 in a single minute
  • Teleporting: FJ can move from any point X to the point 2 × 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


題意:一頭牛逃跑了,跑到了KK處,牛不會動。人從NN處追這頭牛,在一條數軸上行走。人可以移動到N1N-1N+1N+12N2*N處,每次移動消耗一分鐘。要求最少的追到牛的時間。

思路:在我看來,這道題用來做BFS入門很合適,與之前做過的“Red And Black”相比,這個可以說是一維的,是一個一維的遍歷。然後有三種情況,分別是前進一步,後退一步,前進二倍的步數。因此也可以說是在遍歷一個三叉樹。由於是無權最短路,因此用BFS是最合適的。

以題目的示例爲例:
在這裏插入圖片描述注意:

  • 第一點,這裏不會只輸入一個NKN \quad K,HDU一向都是在一個程序中測試多個用例,我一開始沒注意到;
  • 由於每個結點擴展出三個結點,因此遍歷的複雜度飛速上升;我們必須用邊界剪去一些“樹枝”,不然會超過空間。

剪枝:

  • 擴展時,用一個visvis數組記錄,不能擴展出已經走過的節點,即不能回退,以免陷入無效的重複擴展和可能的循環;
  • 如果輸入的N>KN \gt K,那麼只有往後走一條路,因此只需要NKN - K分鐘;
  • 如果當前的val10val - 1 \geq 0,才擴展val1val - 1結點;
  • 如果當前的val+1100,000val + 1 \leq 100,000,才擴展val+1val + 1結點;
  • 如果當前的val2100,000val * 2 \leq 100,000,才擴展2val2 * val結點。

最終,我們最多隻會擴展出100,000100,000左右個結點,大大降低了複雜度。

代碼如下:
這裏我沒有使用傳統的BFS寫法,使用一個structstruct包裹一個表示層數的變量,而是每次直接一個forfor循環將下一層可擴展的結點壓入隊列中。因此找到牛的時候需要一次性跳出兩重循環,所以用了gotogoto,不用也可以,不過多寫幾句。

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章