题目链接

变幻莫测

题目描述

给定两个整数 (),你可以任意顺序多次执行以下两种操作之一:

  1. 交换:
  2. 变换:

求使 成立所需的最少操作次数;如无法实现,输出

解题思路

这是一个典型的求解最短路径问题,最直接和简单的方法是使用广度优先搜索 (BFS)

我们可以把每对 看作一个状态,题目中的两种操作就是连接不同状态的路径。我们的目标是从初始状态 出发,找到到达任意一个满足 的目标状态的最短需要多少步。

BFS 的核心思想是“逐层搜索”,这保证了我们第一次找到目标状态时,所经过的路径一定是最短的。

BFS 实现步骤:

  1. 队列: 创建一个队列,用于存放待访问的状态。每个状态包含三个信息:当前的 值,当前的 值,以及到达此状态所用的步数。
  2. Visited 集合: 创建一个集合,用于记录已经访问过的状态,以防止重复搜索或陷入无限循环。
  3. 初始化: 将初始状态 和步数 加入队列和 visited 集合。
  4. 循环搜索:
    • 从队列头部取出一个状态 (curr_x, curr_y, steps)
    • 对该状态应用“交换”操作,得到新状态 (next_x_1, next_y_1)
    • 对该状态应用“变换”操作,得到新状态 (next_x_2, next_y_2)
    • 对于这两个新状态,分别进行检查:
      • 如果 x == y,说明已到达目标,直接返回 steps + 1
      • 如果该状态未被访问过,并且其数值在某个合理的边界内(例如绝对值小于400,防止无限增长),则将其加入队列和 visited 集合。
  5. 结束条件: 如果队列为空,说明在所有可达范围内都无法找到解,返回

代码

#include <iostream>
#include <queue>
#include <set>
#include <utility>
#include <cmath>

using namespace std;

int main() {
    long long x, y;
    cin >> x >> y;

    if (x == y) {
        cout << 0 << '\n';
        return 0;
    }

    queue<pair<pair<long long, long long>, int>> q;
    set<pair<long long, long long>> visited;
    
    q.push({{x, y}, 0});
    visited.insert({x, y});
    
    long long bound = 400; // 搜索边界

    while (!q.empty()) {
        pair<long long, long long> curr = q.front().first;
        int steps = q.front().second;
        q.pop();

        pair<long long, long long> next_states[2];
        next_states[0] = {curr.second, curr.first}; // 交换
        next_states[1] = {curr.first + curr.second, curr.first - curr.second}; // 变换

        for (const auto& next : next_states) {
            if (next.first == next.second) {
                cout << steps + 1 << '\n';
                return 0;
            }
            if (visited.find(next) == visited.end() && abs(next.first) < bound && abs(next.second) < bound) {
                visited.insert(next);
                q.push({next, steps + 1});
            }
        }
    }

    cout << -1 << '\n';
    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long x = sc.nextLong();
        long y = sc.nextLong();

        if (x == y) {
            System.out.println(0);
            return;
        }

        Queue<State> queue = new LinkedList<>();
        Set<State> visited = new HashSet<>();

        State startState = new State(x, y, 0);
        queue.add(startState);
        visited.add(startState);

        long bound = 400; // 搜索边界

        while (!queue.isEmpty()) {
            State current = queue.poll();
            
            State[] nextStates = new State[2];
            nextStates[0] = new State(current.y, current.x, current.steps + 1); // 交换
            nextStates[1] = new State(current.x + current.y, current.x - current.y, current.steps + 1); // 变换

            for (State next : nextStates) {
                if (next.x == next.y) {
                    System.out.println(next.steps);
                    return;
                }
                if (!visited.contains(next) && Math.abs(next.x) < bound && Math.abs(next.y) < bound) {
                    visited.add(next);
                    queue.add(next);
                }
            }
        }
        System.out.println(-1);
    }
}

class State {
    long x, y;
    int steps;
    State(long x, long y, int steps) { this.x = x; this.y = y; this.steps = steps; }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        State state = (State) o;
        return x == state.x && y == state.y;
    }
    @Override
    public int hashCode() { return Objects.hash(x, y); }
}
from collections import deque
import math

x, y = map(int, input().split())

if x == y:
    print(0)
else:
    q = deque([((x, y), 0)])
    visited = {(x, y)}
    bound = 400 # 搜索边界
    found = False

    while q:
        (curr_x, curr_y), steps = q.popleft()
        
        next_states = [
            (curr_y, curr_x), # 交换
            (curr_x + curr_y, curr_x - curr_y) # 变换
        ]
        
        for next_x, next_y in next_states:
            if next_x == next_y:
                print(steps + 1)
                found = True
                break
            if (next_x, next_y) not in visited and abs(next_x) < bound and abs(next_y) < bound:
                visited.add((next_x, next_y))
                q.append(((next_x, next_y), steps + 1))
        
        if found:
            break
    
    if not found:
        print(-1)

算法及复杂度

  • 算法:广度优先搜索 (BFS)。
  • 时间复杂度:取决于有界状态空间的大小。设边界为 , 状态数约为 。在每个状态,我们执行常数次操作。因此,时间复杂度近似为
  • 空间复杂度:主要由队列和已访问集合占用,与状态数成正比,即