1111就要来了。。。

当你工作了,就没有学校那么多时间了来学习了。。。今年的1111又要来了。。只是。。只是。。。


沉淀吧

学习吧

还是沉淀吧

沉淀下来了才是自己的

平时多总结用过的,学习过的,经历过的


试着去做的更好



你这个问题提得非常好!我们来**逐行分析你的代码**,并解释: > ❓ **为什么这个写法是错误的?** --- ## ✅ 你的目标 你想通过“贪心”方法尝试不同顺序的“完美回文数”(比如先大后小),然后取最小结果。 你用了两个数组: ```c int numbers[3] = {1111, 1001, 11}; // 顺序:1111 → 1001 → 11 int o[3] = {1001, 1111, 11}; // 顺序:1001 → 1111 → 11 ``` 然后分别调用 `x(n, numbers)` 和 `x(n, o)`,比较哪个更小,输出较小值。 你以为这样能“绕过贪心缺陷”。 但很遗憾:❌ **仍然不对!** --- ## 🔍 我们来用一个关键例子测试:$ n = 2002 $ ### 正确答案应该是多少? $$ 2002 = 1001 + 1001 \quad \Rightarrow \text{只需 } 2 \text{ 个} $$ ✅ 所以正确输出应为:`2` --- ### 测试你的函数 `x(n, numbers)` —— 使用 `{1111, 1001, 11}` ```c int x(int a, int numbers[]) { int q = 0; int i = 0; while (i != 3) { if (a / numbers[i] > 0) { q += a / numbers[i]; // 加上能用几个 a = a % numbers[i]; // 剩下的余数 } i++; } return q; } ``` #### 执行过程:`a = 2002`, `numbers = {1111, 1001, 11}` 1. `i=0`: `numbers[0]=1111` - $ 2002 / 1111 = 1 $ → `q += 1` → `q=1` - $ 2002 \% 1111 = 891 $ - `a = 891` 2. `i=1`: `numbers[1]=1001` - $ 891 < 1001 $ → 跳过 3. `i=2`: `numbers[2]=11` - $ 891 / 11 = 81 $ → `q += 81` → `q = 1 + 81 = 82` - $ 891 \% 11 = 0 $ → 返回 `82` --- ### 再试另一个顺序:`o = {1001, 1111, 11}` #### `x(2002, o)` 1. `i=0`: `1001` - $ 2002 / 1001 = 2 $ → `q += 2` → `q=2` - $ 2002 \% 1001 = 0 $ - `a = 0` 2. `i=1`: `1111` → `0/1111=0` → 跳过 3. `i=2`: `11` → `0/11=0` → 跳过 → 返回 `2` --- ### 比较: - `g = 82` - `e = 2` - 输出:`2` ✅ 看起来对了? --- ## 🚨 但是!!!问题来了: 你只试了两种顺序: - `{1111,1001,11}` - `{1001,1111,11}` 那你有没有试过其他数?比如: ### ❌ 反例:$ n = 3003 $ 我们知道: $$ 3003 = 1001 \times 3 \quad \Rightarrow \text{答案是 } 3 $$ 但让我们看看你的程序会不会出错。 #### 用 `o = {1001, 1111, 11}` 的顺序: 1. `3003 / 1001 = 3` → `q=3` 2. `3003 % 1001 = 0` → 后面全跳过 → 返回 `3` ✅ #### 用 `numbers = {1111,1001,11}`: 1. `3003 / 1111 = 2` → `q=2`,余 `3003 - 2×1111 = 781` 2. `781 / 1001 = 0` → 跳过 3. `781 / 11 = 71` → `q += 71` → 总共 `2+71=73` → 返回 `73` → 最终输出 `min(73,3)=3` ✅ 还是对的 --- ## 🧪 再来一个致命反例:$ n = 2112 $ 你知道怎么凑最好吗? 试试: - $ 2112 = 1111 + 1001 $?→ $ 1111+1001=2112 $ ✅ - 只需 **2 个** 所以我们期望输出 `2` --- ### 测试你的两个顺序: #### 顺序一:`{1111,1001,11}` 1. `2112 / 1111 = 1` → `q=1`,余 `1001` 2. `1001 / 1001 = 1` → `q=2`,余 `0` 3. 结束 → 返回 `2` ✅ #### 顺序二:`{1001,1111,11}` 1. `2112 / 1001 = 2` → `q=2`,余 `2112 - 2002 = 110` 2. `110 / 1111 = 0` → 跳过 3. `110 / 11 = 10` → `q += 10` → 总 `2+10=12` → 返回 `12` → 输出 `min(2,12)=2` ✅ 对了 --- ## ✅ 看起来运气不错?那是不是就对了? ### ❌ 不!再来一个真正的问题:$ n = 1122 $ 你能想到最优解吗? #### 最优解: - $ 1122 = 11 \times 102 $ → 需要 102 个 ❌ 太多 - 或者:有没有更好的? 等等……试试: - $ 1111 $ 是可用的 - $ 1122 - 1111 = 11 $ - 所以:$ 1122 = 1111 + 11 $ → 只需 **2 个** ✅ 所以答案是 `2` --- ### 测试你的两个顺序: #### 顺序一:`{1111,1001,11}` 1. `1122 / 1111 = 1` → `q=1`,余 `11` 2. `11 / 1001 = 0` → 跳过 3. `11 / 11 = 1` → `q += 1` → `q=2` → 返回 `2` ✅ #### 顺序二:`{1001,1111,11}` 1. `1122 / 1001 = 1` → `q=1`,余 `121` 2. `121 / 1111 = 0` → 跳过 3. `121 / 11 = 11` → `q += 11` → `q=12` → 输出 `min(2,12)=2` ✅ 还是对了…… --- ## 🤔 那到底错在哪? ### ❌ 错在:你无法枚举所有可能的组合方式! 例如: > $ n = 1111 + 11 = 1122 $ ✅ > $ n = 1001 + 11×11 = 1001+121=1122 $ ✅ > 但这两种路径中,只有前者用了 2 个数,后者用了 12 个 而你的贪心永远只会从左到右“尽可能多地用当前数”,**不能回头选择更优组合** --- ## 💥 终极反例:$ n = 2222 $ ### 最优解: - $ 2222 = 1111 \times 2 $ → 只需 **2 个** ✅ 但如果你的顺序是 `{1001,1111,11}`: #### `x(2222, o)` → `o={1001,1111,11}` 1. `2222 / 1001 = 2` → `q=2`,余 `2222 - 2002 = 220` 2. `220 / 1111 = 0` → 跳过 3. `220 / 11 = 20` → `q += 20` → 总 `2+20=22` → 返回 `22` 而另一个顺序 `{1111,1001,11}`: 1. `2222 / 1111 = 2` → `q=2`,余 `0` → 后面都是0 → 返回 `2` → 输出 `min(22,2)=2` ✅ 又碰巧对了! --- ## ✅ 所以你现在的做法: - 枚举了**两种不同的贪心顺序** - 取最小值 - 在很多情况下会“碰巧正确” - 特别是当某一种顺序恰好选到了最优解时 --- ## ❌ 但它本质上仍是“贪心”,存在致命缺陷: ### 🚫 它无法处理以下情况: > 存在一个最优解,它既不是先用 1111,也不是先用 1001,而是需要“留空某个大数”以便更好地组合。 但你的算法没有“搜索”能力,也没有“回溯”或“动态规划”机制。 --- ## ✅ 正确做法必须使用 **动态规划(完全背包)** 像这样: ```c dp[0] = 0; for (int i = 0; i < 3; i++) { for (int j = pals[i]; j <= 100000; j++) { dp[j] = min(dp[j], dp[j - pals[i]] + 1); } } ``` 这样才能保证:**无论哪种组合方式,都能被考虑到** --- ## 🔚 总结:你为什么不能这么写? | 问题 | 解释 | |------|------| | ✅ 你写了两种顺序取最小 | 是个聪明的优化,能解决部分贪心错误 | | ❌ 但仍然是贪心 | 贪心策略不具备全局最优性保障 | | ❌ 没有遍历所有组合 | 缺少动态规划或搜索机制,会漏掉真正最优解(虽然目前没暴露) | | ❌ 扩展性差 | 如果增加更多“完美回文数”,你需要枚举 $ n! $ 种顺序,不可行 | --- # 知识点(列出该代码中遇到的知识点) - **贪心算法局限性**:局部最优选择无法保证全局最优,如优先使用大数可能导致整体用量增多。 - **模运算与整除贪心**:通过 `a / v` 和 `a % v` 实现快速减法模拟,但忽略组合可能性。 - **多顺序取最小仍非最优**:即使尝试多种贪心顺序,也无法覆盖所有合法组合路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值