【问题标题】:Father, two sons, 999 paintings父亲,两个儿子,999幅画
【发布时间】:2014-10-02 22:25:55
【问题描述】:

这是一个求职申请的问题: “一个父亲有两个儿子,999幅画。每幅画都有不同的价值:第一幅价值1,第二幅价值2,以此类推,直到最后一幅价值999。他想把他所有的画分成他的两幅。儿子,让每个儿子都得到平等的价值。999幅画有多少种方法? 例子:如果父亲有 7 幅画,他可以通过给第一个儿子画 1,6 和 7 来公平分配它们。第二个儿子将得到 2,3,4 和 5。两者的总和值相等,14。如果有 7 幅画,父亲可以将它们公平地分成 4 种方式(其他 3 种此处未列出),因此解决方案为 4。 提示:这个数字可能很大,所以请将您的解决方案的最后 10 位数字和草图发送给我们。”

我所做的是尝试使用蛮力方法,通过编写一个 c# 程序来添加所有可能的组合,该程序编写它自己的 c# 程序,循环内有循环,如下所示:

StringBuilder sb = new StringBuilder();
for (short i = 2; i <= 999; i++) //starts from 2 because 1 is always added to the total for one side
{
    sb.AppendLine("for (byte i" + i.ToString() + " = 0; i" + i.ToString() + " < 2; i" + i.ToString() + "++)");
    sb.AppendLine("{");
}

for (int i = 2; i <= 999; i++)
{
    sb.Append("if (i" + i.ToString() + " == 1) { total += " + i.ToString() + "; }\n");
}

for (short i = 2; i <= 999; i++)
{
    sb.AppendLine("}");
}

然后在结果中的 if 块之后添加:

if (total == 249750)
{
    count++; //count is a BigInteger
}
total = 1;

这种方法在技术上应该可行(在少量绘画上进行了测试),但问题是它是一个巨大的数字,在我的计算机上以这种方式计算结果需要大约一百万年......是否有一些数学技巧可以在合理的时间内做到这一点?

【问题讨论】:

  • 见鬼,这超出了我的范围:D 目前,至少...
  • 是的,我明白这一点,我问不是为了在面试中作弊,我问是为了学习新的东西,并希望为我的技能增加一些新的东西。我发布了链接,以防万一有能力解决问题的人可以申请并满足要求。 (它被mod编辑了,显然这是违反规则的)
  • 编码前三思。手动计算一些较小的问题案例。有图案吗?设 f(n) 为 n 幅画的等分分割数。你能写出 f(n) 的递推关系吗?如果没有,定义部分解决方案功能有帮助吗?提示:设 g(n, t) 为长子获得总价值 t 的 n 幅画的分割数。

标签: c# .net algorithm math


【解决方案1】:

更容易解决更一般的问题,即确定第一个儿子可以通过多少种方式获得价值k,其中k 是一个参数。找出适当的概括是一门艺术。它在算法课程中以动态编程的名义教授。

x 成为一个变量。所需的数学洞察力是,对于n 绘画,多项式乘积中x^k 的系数

x (1 + x^2) (1 + x^3) ... (1 + x^n)

inx是第一个儿子获得价值k的方式数量(包括价值1的绘画)。这是因为该产品分发给

(sum for i_2 = 0 to 1) (sum for i_3 = 0 to 1) ... (sum for i_n = 0 to 1)
    x^(1 + 2 i_2 + 3 i_3 + ... + n i_n),

这实际上是您的蛮力解决方案评估此产品的方式。这里的动态程序相当于将因子一个一个分配,而不是一次全部分配,例如,

x (1 + x^2) = x + x^3
x (1 + x^2) (1 + x^3) = (x + x^3) (1 + x^3)
                      = x + x^3 + x^4 + x^6.
x (1 + x^2) (1 + x^3) (1 + x^4) = (x + x^3 + x^4 + x^6) (1 + x^3)
                                = x + x^3 + x^4 + x^6 + x^4 + x^6 + x^7 + x^9
                                = x + x^3 + 2 x^4 + 2 x^6 + x^7 + x^9.

时间节省来自重复条款。我们已经只有​​六个项要处理,而不是八个(二的三次方)。

只保留最后十位数字意味着我们可以在整数环中以 10^10 为模来评估这个产品。因此,我们可以减少以该数字为模的中间系数,以避免求助于 bignums。这个技巧在竞争激烈的编程社区中广为人知,在抽象代数或数论课程中正式介绍过。

Mathematica:

In[1]:= Coefficient[x Product[1+x^i,{i,2,7}],x^(Sum[i,{i,1,7}]/2)]

Out[1]= 4

In[2]:= Coefficient[x Product[1+x^i,{i,2,8}],x^(Sum[i,{i,1,8}]/2)]

Out[2]= 7

在 Java 中:

public class PartitionPaintings {
    public static void main(String[] args) {
        long[] p = new long[] {0, 1};
        for (int i = 2; i <= Integer.parseInt(args[0]); i++) {
            long[] q = new long[p.length + i];
            for (int k = 0; k <= p.length - 1; k++) {
                for (int j = 0; j <= 1; j++) {
                    q[k + i * j] = (q[k + i * j] + p[k]) % 10000000000L;
                }
            }
            p = q;
        }
        System.out.println(p[(p.length - 1) / 2]);
    }
}

【讨论】:

  • “这个技巧,在竞争激烈的编程社区中广为人知......”我知道其中有一个技巧 :D 现在因为我不明白你所说的大部分内容,你知道抽象代数或数论的免费在线课程好吗?
  • @infamous 我个人没有什么可以推荐的。仅仅学习模运算就足以应付最后 n 位(模 m)的输出要求。请注意,真正的加速来自切换多项式乘法算法。
  • 答案几乎是有道理的。除了对于模算术部分的应用,即保持数字低而不需要BigInteger ...事实证明, 10^10 是一个很好的用于 mod 的数字,基于答案长度小于 10 位的假设......但是,事实并非如此......在这段代码中用 BigInteger 替换 long 给出了 完全 不同的答案.. 100 位长....如果我还是弄错了,请有人澄清。
  • @DavidEisenstat 另外,我不是数学专业的.. 可能听起来很愚蠢,但我肯定很好奇,你如何获得与答案相关的多项式的洞察力(以及它的系数和东西)(希望答案不是数学博士)?
  • @VikasGupta Generating functions 可以用于很多很酷的事情。取模的业务是因为只需要找到可行分区数的后十位即可。
【解决方案2】:

这是一份数学工作。

你基本上是在寻找number partition,一个distinct parts

所有画作的总价值是整数 1…999 的总和。 (n * (n+1)) / 2according to Gauss,所以我们得到:(999 * 1000) / 2 = 499500。所以每个儿子应该得到总价值249750的画。

现在,我们只需要找到该值的不同部分不超过 999 的分区数。我们将找到的每个分区分配为一个儿子的绘画集,第二个儿子将获得剩余的绘画 (总价值相同)。

所以唯一棘手的部分是找出不同部分和有界部分的分区函数。但我想你也可以通过编程方式来做到这一点。

来自德黑兰谢里夫科技大学的 Mohammadreza Bidar 实际上写了一篇论文,题目很有希望“将整数划分为不同的有界部分、标识和边界”。你可以在INTEGERS, volume 12阅读它(这是那里的第8篇文章)。

【讨论】:

  • 499500 是总值,所以每个儿子应该得到一半(249750),这是容易的部分。不知道那个高斯公式,但我已经用 for 循环做到了,我跳过了问题中的那部分,对不起,应该更清楚...
  • 对不起,我是想写那个数字,不知道为什么不写。
  • 这是如何解决问题的?
猜你喜欢
  • 2013-03-14
  • 1970-01-01
  • 1970-01-01
  • 2019-05-24
  • 2021-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多