当前位置: 首页 > news >正文

[过程记录] 《分寝室》 一题做法思考

[过程记录] 《分寝室》 一题做法思考

@Author: Kai

@Time: 2025-03-20

从错误的解题思路开始,一直怀疑 L1 哪有那么难,直到使用遍历发现 10e5 并没有很大。记录下这个曲折的过程。

题目

L1-7 分寝室

学校新建了宿舍楼,共有 n 间寝室。等待分配的学生中,有女生 n0 位、男生 n1位。所有待分配的学生都必须分到一间寝室。所有的寝室都要分出去,最后不能有寝室留空。
现请你写程序完成寝室的自动分配。分配规则如下:

  • 男女生不能混住;
  • 不允许单人住一间寝室;
  • 对每种性别的学生,每间寝室入住的人数都必须相同;例如不能出现一部分寝室住 2 位女生,一部分寝室住 3 位女生的情况。但女生寝室都是 2 人一间,男生寝室都是 3 人一间,则是允许的;
  • 在有多种分配方案满足前面三项要求的情况下,要求两种性别每间寝室入住的人数差最小。

输入格式
输入在一行中给出 3 个正整数 n0、n 1 、n,分别对应女生人数、男生人数、寝室数。数字间以空格分隔,均不超过 10 5

输出格式
在一行中顺序输出女生和男生被分配的寝室数量,其间以 1 个空格分隔。行首尾不得有多余空格。
如果有解,题目保证解是唯一的。如果无解,则在一行中输出No Solution

输入样例 1

24 60 10

输出样例 1

4 6

注意:输出的方案对应女生都是 24/4=6 人间、男生都是 60/6=10 人间,人数差为 4。满足前三项要求的分配方案还有两种,即女生 6 间(都是 4 人间)、男生 4 间(都是 15 人间);或女生 8 间(都是 3 人间)、男生 2 间(都是 30 人间)。但因为人数差都大于 4 而不被采用。

输入样例 2

29 30 10

输出样例 2

No Solution

分析

这道题满足一个式子:

在这里插入图片描述

设男生寝室数量为x,女生寝室数量为y,那么有关系:

min ⁡ ∣ 男生总数 x − 女生总数 y ∣ x + y = 房间总数 \begin{matrix} \min \left | \frac{男生总数}{x} - \frac{女生总数}{y} \right | \\ x+y=房间总数 \end{matrix} min x男生总数y女生总数 x+y=房间总数

  1. 约束条件分析
    根据 x + y = C x + y = C 4 x+y=Cx+y=C4 x+y=Cx+y=C4,可得 y = C − x y = C − x y=C−xy=C−x y=Cxy=Cx。因此,x 需满足:

    2 ≤ x ≤ A 2 ≤ y = C − x ≤ B \begin{matrix} 2≤x≤A \\ 2≤y=C−x≤B \end{matrix} 2xA2y=CxB

    x 的有效范围为:

    x m i n = max ⁡ ( 2 , C − B ) , x m a x = min ⁡ ( A , C − 2 ) x_{min} = \max (2, C-B), x_{max} = \min (A, C-2) xmin=max(2,CB),xmax=min(A,C2)

  2. 遍历可行解
    遍历 xx 的有效范围,计算对应的 y = C − x y=C-x y=Cx,并检查 y 是否在 [2,B] 内。对于每个有效的 (x,y),计算 $\left | \frac{A}{x}-\frac{B}{y} \right | $,记录最小值对应的解。

  3. 直接返回最小解
    若存在多个解具有相同的最小绝对值,返回任意一个(例如第一个找到的解)。

解法

def find_min_abs_diff(A, B, C):
    """
    寻找满足 x + y = C, 2 <= x <= A, 2 <= y <= B 的正整数解 (x, y),
    使得 |A/x - B/y| 最小。若存在,返回 (x, y);否则返回 None。
    """
    x_min = max(2, C - B)  # x的下限:确保y = C - x <= B
    x_max = min(A, C - 2)  # x的上限:确保y = C - x >= 2
    
    if x_min > x_max:
        return None  # 无解
    
    min_abs = float('inf')
    best_x, best_y = None, None
    
    for x in range(x_min, x_max + 1):
        y = C - x
        if y < 2 or y > B:
            continue  # y不满足条件
        
        current_abs = abs(A / x - B / y)
        
        if current_abs < min_abs:
            min_abs = current_abs
            best_x, best_y = x, y
    
    return (best_x, best_y) if best_x is not None else None
  1. 计算 x 的范围
    • x_min = max(2, C - B):确保 y=CxB
    • x_max = min(A, C - 2):确保 y=Cx≥2。
  2. 遍历并验证解
    • 遍历 xx_minx_max,计算对应的 y=Cx
    • 检查 y 是否在 [2,B] 内。
    • 计算绝对值并更新最小值。
  3. 边界处理
    • x_min > x_max,直接返回 None
    • 若遍历结束后未找到有效解,返回 None

针对极大 C 的优化

通过分析目标函数 $\left | \frac{A}{x}-\frac{B}{C-x} \right | $,找到理论最优解附近的候选点,避免完全遍历。


推导步骤

  1. 目标函数化简
    忽略绝对值,定义函数:

    $f(x) = \frac{A}{x} - \frac{B}{C-x} $

    寻找 f(x)=0 的解,即:

    $\frac{A}{x} = \frac{B}{C-x} \Longrightarrow x = \frac{A·C}{A+B} $

    记理论最优解为 $x_{0} = \frac{A·C}{A+B} $。

  2. 确定候选范围
    实际解需满足 x∈[xmin,xmax]。只需检查 x0 附近的整数点(如 ⌊x0⌋−2 到 ⌊x0⌋+2),计算所有候选点的 ∣f(x)∣。

  3. 边界处理
    x0​ 超出有效范围,则直接检查边界点 xmin​ 和 xmax​。

代码

def optimized_min_abs_diff(A, B, C):
    """
    针对极大 C 的优化算法,直接定位候选点附近求解。
    """
    x_min = max(2, C - B)
    x_max = min(A, C - 2)
    
    if x_min > x_max:
        return None
    
    # 计算理论最优解 x0
    x0 = (A * C) / (A + B)
    candidates = []
    
    # 生成候选点(覆盖 x0 附近的整数)
    for dx in [-2, -1, 0, 1, 2]:
        candidates.append(int(x0 + dx))
    
    # 添加边界点
    candidates.extend([x_min, x_max])
    
    # 去重并过滤无效点
    valid_x = set()
    for x in candidates:
        if x_min <= x <= x_max:
            valid_x.add(x)
    
    # 遍历候选点
    min_abs = float('inf')
    best_x, best_y = None, None
    for x in valid_x:
        y = C - x
        if y < 2 or y > B:
            continue
        current_abs = abs(A / x - B / y)
        if current_abs < min_abs:
            min_abs = current_abs
            best_x, best_y = x, y
    
    return (best_x, best_y) if best_x is not None else None

# 示例测试
if __name__ == "__main__":
    # 示例1: A=1000, B=2000, C=1e6 → 理论解 x0=333333.333...
    print(optimized_min_abs_diff(1000, 2000, 10**6))  # 输出 (333333, 666667)
    
    # 示例2: A=3, B=6, C=6 → 解为 (2,4)
    print(optimized_min_abs_diff(3, 6, 6))  # 输出 (2, 4)

误区

最开始设定:男生每个房间的人数为 x,女生每个房间的人数为 y

步骤一:方程变形与条件分析

那么有关系:

A x + B y = C \frac{A}{x} + \frac{B}{y} = C xA+yB=C

将其两边乘以 xy 得:

A y + B y = C x y Ay+By =Cxy Ay+By=Cxy

整理为:

( C x − A ) ( C y − B ) = A B (Cx−A)(Cy−B)=AB (CxA)(CyB)=AB

此时,C**xAC**yB 必须为正整数,即:

$x > \frac{A}{C}, y > \frac{B}{C} $

步骤二:存在性条件

方程存在正整数解当且仅当 AB 能分解为两个正整数 pq 的乘积,满足:

p ≡ − A (   m o d   C ) , q ≡ − B (   m o d   C ) p\equiv -A (\bmod C ), q\equiv -B (\bmod C ) pA(modC),qB(modC)

且对应的解为:

$x=\frac{p+A}{C}, y=\frac{q+B}{C} $

其中 xy 均为正整数。

步骤三:求解步骤

  1. 分解因数对:列出 AB 的所有正因数对 (p,q),即 pq=AB
  2. 筛选同余条件:保留满足 p ≡ − A (   m o d   C ) , q ≡ − B (   m o d   C ) p\equiv -A (\bmod C ), q\equiv -B (\bmod C ) pA(modC),qB(modC)的因数对。
  3. 计算解:对每个符合条件的 (p,q),计算 x = p + A C , y = q + B C x=\frac{p+A}{C}, y=\frac{q+B}{C} x=Cp+A,y=Cq+B,并验证是否为正整数。
  4. 最小化:在所有解中,选择 ∣xy∣ 最小的解。

代码

def find_min_abs_diff_solution(A, B, C):
    """
    求解方程 A/x + B/y = C 的正整数解,并返回使得 |x - y| 最小的解 (x, y)
    若无解则返回 None
    """
    product = A * B
    factor_pairs = []
    # 生成所有正因数对 (p, q),满足 p * q = A*B
    for i in range(1, int(product**0.5) + 1):
        if product % i == 0:
            factor_pairs.append((i, product // i))
            if i != product // i:  # 避免重复添加平方数情况
                factor_pairs.append((product // i, i))
    
    valid_solutions = []
    required_p_mod = (-A) % C  # p需要满足的同余条件
    required_q_mod = (-B) % C  # q需要满足的同余条件
    
    for p, q in factor_pairs:
        # 检查同余条件和整除性
        if (p % C == required_p_mod) and (q % C == required_q_mod):
            # 计算x和y,并验证是否为正整数
            if (p + A) % C == 0 and (q + B) % C == 0:
                x = (p + A) // C
                y = (q + B) // C
                if x > 0 and y > 0:  # 确保x和y为正整数
                    valid_solutions.append((x, y))
    
    if not valid_solutions:
        return None  # 无解
    
    # 找出 |x - y| 最小的解
    min_diff = float('inf')
    best_solution = None
    for x, y in valid_solutions:
        current_diff = abs(x - y)
        if current_diff < min_diff:
            min_diff = current_diff
            best_solution = (x, y)
        elif current_diff == min_diff:
            # 如果存在多个解差值相同,可在此处添加选择逻辑(如优先x+y最小)
            pass
    
    return best_solution

# 示例测试
if __name__ == "__main__":
    # 示例1: A=2, B=3, C=1 → 解为 (5,5)
    print(find_min_abs_diff_solution(2, 3, 1))  # 输出 (5,5)
    
    # 示例2: A=3, B=4, C=2 → 解为 (3,4)
    print(find_min_abs_diff_solution(3, 4, 2))  # 输出 (3,4)
    
    # 示例3: A=1, B=1, C=3 → 无解
    print(find_min_abs_diff_solution(1, 1, 3))  # 输出 None

该算法的时间复杂度主要由以下两个步骤决定:

  1. 生成所有因数对:时间复杂度为 O(√(A·B))
    通过遍历从 1 到 √(A·B) 的所有整数,寻找 A·B 的因数对。每次循环需要常数时间,总循环次数为 √(A·B)。
  2. 筛选因数对并验证条件:时间复杂度为 O(d(A·B))
    其中 d(A·B) 是 A·B 的因数总数。对于每个因数对 (p, q),检查同余条件和计算解需要常数时间。
综合时间复杂度:O(√(A·B) + O(d(A·B))
  • √(A·B) 的主导性
    对于大多数情况,√(A·B) 远大于 d(A·B)(例如 A·B = 1e6 时,√(A·B)=1e3,而 d(A·B)=36)。因此,总时间复杂度通常由 O(√(A·B)) 主导。
  • 极端情况下的表现
    如果 A·B 是平方数且因数较多(例如 A·B=2^30),d(A·B)=31,此时时间复杂度主要由 √(A·B)=2^15=32768 决定。

优化与局限性

  1. 适用性
    该算法在 A 和 B 较小时高效,但当 A·B 极大时(例如 A=1e18, B=1e18),√(A·B)=1e9 次循环会超出时间限制。
  2. 改进方向
    若问题允许,可结合质因数分解优化因数生成,或利用数学性质直接构造解,避免完全遍历。但对于通用情况,当前方法已是最优。

该文章有 DeepSeek 参与。
36)。因此,总时间复杂度通常由 O(√(A·B)) 主导。

  • 极端情况下的表现
    如果 A·B 是平方数且因数较多(例如 A·B=2^30),d(A·B)=31,此时时间复杂度主要由 √(A·B)=2^15=32768 决定。

优化与局限性

  1. 适用性
    该算法在 A 和 B 较小时高效,但当 A·B 极大时(例如 A=1e18, B=1e18),√(A·B)=1e9 次循环会超出时间限制。
  2. 改进方向
    若问题允许,可结合质因数分解优化因数生成,或利用数学性质直接构造解,避免完全遍历。但对于通用情况,当前方法已是最优。

该文章有 DeepSeek 参与。

相关文章:

  • 基于springboot的教务系统(源码+lw+部署文档+讲解),源码可白嫖!
  • 《模型思维》第二十三章 “与集体行动有关的问题” 总结
  • LLM之向量数据库Chroma milvus FAISS
  • AI+视频赋能智慧农业:EasyCVR打造全域可视化农场监管平台
  • AI日报 - 2025年3月20日
  • 《Java核心三问:字符串、equals()、hashCode()的隐藏雷区与完美避坑手册》
  • UltraSearch一键直达文件,高效搜索新体验
  • 双指针算法-day14(分组循环)
  • java数据结构之双端对列
  • 力扣刷题——25.K个一组翻转链表
  • 【全国产化主板】解决方案探讨:CPU、FPGA、GPU、AI的融合与优化
  • 【最后203篇系列】020 rocksdb agent
  • 《视觉SLAM十四讲》ch13 设计SLAM系统 相机轨迹实现
  • Neo4j GDS-04-图的中心性分析介绍
  • 力扣977. 有序数组的平方(双指针技巧)
  • 【STM32】I²CC通信外设硬件I²CC读写MPU6050(学习笔记)
  • kubernetes高级实战
  • 6.3考研408数据结构中BFS与DFS的易错点及难点解析
  • 9、Python collections模块高效数据结构
  • 前端面试常考基础题目详解
  • 旅游局网站的建设情况/百度搜索引擎使用技巧
  • 简约设计网站/设计公司
  • 中建一局集团有限公司官网/优化师培训
  • 杭州网站设计公司哪家好/纯注册app拉新平台
  • 萧山做网站的企业/网站收录批量查询
  • 做网站 做推广需要知道什么/360搜索引擎