A - Catch That Cow
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 ) N (0≤N≤100,000) N(0≤N≤100,000) on a number line and the cow is at a point K ( 0 ≤ K ≤ 100 , 000 ) K (0≤K≤100,000) 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 X X to the points X − 1 X - 1 X−1 or X + 1 X + 1 X+1 in a single minute
- Teleporting: FJ can move from any point X X X to the point 2 × X 2 × X 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
N
N and
K
K
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
5-10-9-18-17
5−10−9−18−17, which takes
4
4
4 minutes.
题目分析
最短路径问题,很容易想到广度优先搜索 (BFS)。因为在BFS中,我们需要用到队列 (queue) 这种数据结构,我们也知道队列的特性是FIFO(first in first out,先进先出),正是这个特性保证了我们第一个到达目标点的路径一定是最短路径。
关于BFS的更为详细的解释可以参考我的上一篇博客:【算法积累】Oil Deposits(DFS&BFS)。
代码
语言:C++
#include <iostream>
#include <queue>
#define MAXSIZE 100005
using namespace std;
int step[MAXSIZE];
bool visited[MAXSIZE];
int bfs(int start, int end) {
queue<int> q;
q.push(start);
visited[start] = true;
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = 0; i < 3; i++) {
int tmp;
switch (i) {
case 0:
tmp = x + 1;
break;
case 1:
tmp = x - 1;
break;
case 2:
tmp = x * 2;
break;
}
if (tmp < 0 || tmp > 100000 || visited[tmp]) {
continue;
}
q.push(tmp);
visited[tmp] = true;
step[tmp] = step[x] + 1;
if (tmp == end) {
return step[end];
}
}
}
return -1;
}
int main() {
int n, k;
cin >> n >> k;
cout << (n >= k ? n - k : bfs(n, k)) << endl;
return 0;
}
语言:Java
import java.util.LinkedList;
import java.util.Scanner;
import java.util.Queue;
public class Main {
public static int[] step = new int[100005];
public static boolean[] visited = new boolean[100005];
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int N = input.nextInt();
int K = input.nextInt();
System.out.println(N >= K ? (N - K) : bfs(N, K));
input.close();
}
public static int bfs(int start, int end) {
Queue<Integer> q = new LinkedList<Integer>();
q.add(start);
visited[start] = true;
while (!q.isEmpty()) {
int x = q.element();
q.remove();
for (int i = 0; i < 3; i++) {
int next = 0;
switch (i) {
case 0:
next = x + 1;
break;
case 1:
next = x - 1;
break;
case 2:
next = x * 2;
break;
}
if (next < 0 || next > 100000 || visited[next]) {
continue;
}
q.add(next);
visited[next] = true;
step[next] = step[x] + 1;
if (next == end) {
return step[end];
}
}
}
return -1;
}
}
B - 轻重搭配
n n n个同学去动物园参观,原本每人都需要买一张门票,但售票处推出了一个优惠活动,一个体重为 x x x的人可以和体重至少为 2 x 2x 2x配对,这样两人只需买一张票。现在给出了 n n n个人的体重,请你计算他们最少需要买几张门票?
输入格式
第一行一个整数
n
n
n,表示人数。
第二行
n
n
n个整数,每个整数
a
i
a_i
ai表示每个人的体重。
输出格式
一个整数,表示最少需要购买的门票数目。
数据范围
对于
30
30%
30的数据:
1
≤
n
≤
25
,
1
≤
a
i
≤
100
1≤n≤25,1≤a_i≤100
1≤n≤25,1≤ai≤100。
对于
60
60%
60的数据:
1
≤
n
≤
10000
,
1
≤
a
i
≤
1000
1≤n≤10000,1≤a_i≤1000
1≤n≤10000,1≤ai≤1000。
对于
100
100%
100的数据:
1
≤
n
≤
5
⋅
1
0
5
,
1
≤
a
i
≤
1
0
5
1≤n≤5⋅10^5,1≤a_i≤10^5
1≤n≤5⋅105,1≤ai≤105。
样例解释
1
1
1和
9
9
9配对,
7
7
7和
3
3
3配对,剩下
5
,
5
5,5
5,5单独,一共买四张票。
Sample Input
6
1 9 7 3 5 5
Sample Output
4
题目分析
不难想到我们最多可以组成
n
/
2
n/2
n/2对,因此可以采用二分的策略,分为前后两组进行查找配对。
代码
语言:C++
#include <bits/stdc++.h>
#define MAXSIZE 500005
using namespace std;
int a[MAXSIZE];
bool flag[MAXSIZE];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
sort(a + 1, a + n + 1);
int mid = n / 2;
int high = n;
int ans = 0;
while (mid) {
if (a[mid] * 2 <= a[high]) {
ans++;
flag[mid] = true;
flag[high] = true;
mid--;
high--;
} else {
mid--;
}
}
for (int i = 1; i <= n; i++) {
if (!flag[i]) {
ans++;
}
}
cout << ans << endl;
return 0;
}
语言:Java
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static int[] a = new int[500005];
public static boolean[] flag = new boolean[500005];
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
for (int i = 1; i <= n; i++) {
a[i] = input.nextInt();
}
Arrays.sort(a, 1, n + 1);
int mid = n / 2;
int high = n;
int ans = 0;
while (mid != 0) {
if (a[mid] * 2 <= a[high]) {
ans++;
flag[mid] = true;
flag[high] = true;
mid--;
high--;
} else {
mid--;
}
}
for (int i = 1; i <= n; i++) {
if (!flag[i]) {
ans++;
}
}
System.out.println(ans);
input.close();
}
}