首页 > 试题广场 >

小红的数位删除

[编程题]小红的数位删除
  • 热度指数:631 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
小红拿到了两个正整数ab,她每次操作可以选择其中一个正整数,删除一个数位。例如,对于"1243"而言,进行一次操作可以生成"124"、"123"、"143"或"243"。
小红希望最终ab的倍数或者ba的倍数。她想知道自己最少的操作次数是多少?

输入描述:
两个正整数ab,用空格隔开。
1\leq a,b \leq 10^9


输出描述:
如果无法如何都无法使得ab的倍数或者ba的倍数,则输出-1。
否则输出一个整数,代表小红的最小操作次数。
示例1

输入

37 111

输出

0

说明

111是37的倍数,所以小红不需要任何操作。
示例2

输入

1234 99

输出

2

说明

第一个数删除数字'1',变成234。第二个数删除数字'9',变成9。234是9的倍数。

这道题其实简单喵~

只需要用广度优先搜索(BFS)就可以探索所有可能的状态了喵!

  1. 用结构体 zu 记录当前两个数的值 a、b 和已经操作的次数 cishu。
  2. 从初始状态 (a, b) 开始,不断尝试对其中一个数删除每一位,生成新的数对,并记录步数。
  3. 用 set<pair<int,int>> 记录已经访问过的状态,避免重复探索喵~如果不写的话会爆掉的!
  4. 如果当前两个数能整除(一个数是另一个数的倍数),就输出当前步数,并结束。
  5. 如果队列空了还没找到,就输出 -1,表示猫猫没招了喵!

有思路了就去写喵!

如果只是不会写就看猫猫的代码喵~

#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
using ll=long long;

// 喵~每个组都要记住:当前步数、a的值、b的值
struct zu
{
    ll cishu;  // 已经操作的次数
    ll a, b;   // 两个数当前的值
};

int main() {
    ll a, b;
    cin >> a >> b;  

    queue<zu> q;     // BFS队列
    q.push({0, a, b});  // 初始状态入队,步数为0

    set<pair<int,int>> s;  // 记录已经访问过的 (a, b) 状态,防止重复探索

    while (!q.empty())
    {
        zu now = q.front();  // 取出来最小步数的一组
        q.pop();

        // 检查当前两个数是否满足倍数关系(一个能整除另一个)
        if (now.a % now.b == 0 || now.b % now.a == 0)
        {
            cout << now.cishu;  // 输出当前步数
            return 0;           // 任务完成,喵~
        }

        // 尝试删除 now.a 的每一位
        for (int i = 1; i <= now.a; i *= 10)
        {
            // 删除第 i 位后的新数:高位部分 * i + 低位部分
            int new_a = now.a / (i * 10) * i + now.a % i;
            if (new_a == 0) continue;  // 题目不让全删完喵~

            // 如果这个新状态没访问过,就入队
            if (!s.count({new_a, now.b}))
            {
                s.insert({new_a, now.b});
                q.push({now.cishu + 1, new_a, now.b});
            }
        }

        // 同样,尝试删除 now.b 的每一位
        for (int i = 1; i <= now.b; i *= 10)
        {
            int new_b = now.b / (i * 10) * i + now.b % i;
            if (new_b == 0) continue;
            if (!s.count({now.a, new_b}))
            {
                s.insert({now.a, new_b});
                q.push({now.cishu + 1, now.a, new_b});
            }
        }
    }

    // 如果队列空了还没找到解,就输出-1
    cout << -1;
}
/*
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣤⡀⣀⣠⣤⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⡀⢀⣴⣾⣷⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣷⣾⣿⣷⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⠿⠛⠛⠉⠉⠉⠉⠉⠉⠛⠻⠿⣿⣿⣿⣿⣿⣶⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⡿⠿⠛⠉⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠿⣿⣿⣿⣷⣄⡀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣀⣿⣿⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⣰⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣠⣾⣿⣿⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣶⣄⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣻⣿⣿⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⢹⣿⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⠁⠈⢢⡀⠀⠀⠀⢸⡇⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣿⡟⠒⢦⡀⠀⠀⠀
⠀⠀⣠⣤⣤⣼⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡇⠀⠀⠀⠉⢢⣄⠀⠀⢿⠊⠳⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣷⡄⠀⢷⠀⠀⠀
⠀⢰⠇⠀⣰⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⡌⣹⠗⠦⣬⣇⠀⠉⢢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⡀⢸⡄⠀⠀
⠀⡟⠀⣼⣯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣆⢹⡀⠀⠀⠀⠉⠁⠀⠀⢀⣀⡁⠀⠀⠉⠳⢴⡆⠀⠀⠀⠀⠀⠀⢹⣧⠈⡇⠀⠀
⠀⡇⠀⠀⢻⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣾⠻⠉⠛⠂⠀⠀⠀⠀⠀⠀⠻⠿⣿⣿⣿⣶⣦⡀⠛⣇⠀⠀⠀⠀⠀⣈⣿⠀⡇⠀⠀
⢸⡇⠀⠀⢠⣿⣷⣦⣀⡸⣷⣦⣶⡂⠉⠉⠉⢁⣤⣶⡶⠀⠀⠀⣀⣀⡴⠀⠀⠀⠀⠀⠀⠈⠉⠉⠁⠀⡟⢀⣴⣟⣰⣾⣿⣏⣠⠇⠀⠀
⠈⡇⠀⠀⢸⣿⠁⠉⣿⠛⠛⠃⡇⠀⠀⢠⣶⣿⡿⠛⠁⠀⠀⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⢿⠟⠿⢿⡏⠀⠘⣿⡀⠀⠀⠀
⠀⢷⣀⣀⣿⠇⠀⠀⢿⡇⠀⢀⢱⡀⠀⠛⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⠀⠀⢸⠇⠀⠀⢹⣿⣄⠀⠀
⠀⠀⣉⣿⡏⠀⠀⠀⠀⠀⠀⢸⣇⣳⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⣿⠃⠀⠀⠀⠀⠀⠀⣿⠈⢧⠀
⠀⠘⣿⣿⠁⠀⠀⠀⠀⠀⠀⠘⣿⡛⣶⠀⠀⣠⠔⠒⠛⠒⠦⡀⠀⠀⠀⠀⣠⡤⠶⠤⢤⣀⠀⠀⠀⢀⣏⡄⠀⠀⠀⠀⠀⡀⣿⡆⠈⣧
⣠⡾⠛⣿⣿⣧⠀⠀⠀⠀⢸⣿⠾⢿⡿⠀⣰⠃⠀⠀⠀⠀⠀⢹⡄⠀⠀⡼⠁⠀⠀⠀⠀⠈⠙⣦⠀⢸⣿⡇⣾⣣⡀⠀⢰⣿⣿⣿⣤⠾
⡟⠀⠀⠻⣿⡟⢷⡄⣤⡀⠈⣿⡀⣸⠇⠀⠏⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⡇⢀⡀⠀⠀⠀⠀⢀⡟⠀⠀⠋⣿⣿⣿⡇⣠⣿⠿⠛⢷⡀⠀
⠀⠀⠀⠀⣿⣇⣨⣿⣿⣿⣦⣽⣷⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠃⠀⠙⠢⠤⠤⠴⢾⠀⠀⠀⠀⢸⣷⣿⣿⠟⠁⠀⠀⠈⣧⠀
⠀⠀⠀⠀⠈⠉⠉⠁⠈⠉⠈⢉⣿⡁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⣿⠀
*/


发表于 2026-02-17 10:53:34 回复(0)
应该没有什么规律,直接暴力尝试所有删除方法。
删除次数从小往大尝试,可以提前退出。
那么如何枚举固定删除次数下的结果呢?这里用到了 Gospher‘s Hack. https://read.seas.harvard.edu/~kohler/class/cs207-s12/lec12.html
from functools import cache

a, b = input().split()
n1, n2 = len(a), len(b)

def subset(n, m):
    x = (1 << m) - 1
    mx = x << (n - m)
    while x <= mx:
        yield x 
        y = x & -x 
        c = x + y 
        x = (((x ^ c) >> 2) // y) | c
    return 

@cache
def f(s, m):
    n = len(s)
    arr = list(map(int, s))
    def to_int(x):
        acc = 0
        for i in range(n):
            if x & 1:
                acc *= 10
                acc += arr[i]
            x >>= 1
        return acc 
    return set(map(to_int, subset(n, m)))

def solve():
    for i in range(n1 + n2 - 1):
        for j in range(max(0, i - n2 + 1), min(i + 1, n1)):
            k = i - j 
            for x in f(a, n1 - j):
                for y in f(b, n2 - k):
                    if x % y == 0&nbs***bsp;y % x == 0:
                        return i 
    # return n1 + n2
    # 我寻思 0 是 0 的倍数,那全删完一定可以啊
    # 仔细一想,全删完会得到一个空串,不能解读为数字
    return -1

print(solve())



发表于 2026-02-17 01:30:00 回复(2)