回 帖 发 新 帖 刷新版面

主题:[原创]解金山公司面试题

/*************************************
文件名: 解金山公司面试题
创建人: 陈泽丹
创建时间: 2007年3月10日
版本号: 0.5
*************************************/
/*-------------------------------------------

问题描述:
1000个苹果放在10个箱子里, 10个箱子一模一样且要
求每个箱子都放有苹果, 问共有多少种放法?

-------------------------------------------*/
/*========================================
很遗憾:
我试了150个苹果放10个箱子, 在我的机子上运行10几秒
后得出结果:75611815  也就是说7千万多种放法... 
那1000个苹果呢?...不敢想象其数据...就算我的机
子能运行出来并且我想到更快速的算法解答, 但
我很担心一个问题:其结果会不会是一个天文数字? 会不会溢
出双精度的范围了...即是说能算出来,但还需使用技巧来表
示出这个数字这就加大了编程的麻烦性,而我现在没有太多的
时间可用.
所以对这题的解答先写到这吧, 很有遗憾!有时间我一定
会再来写这道题的!
===========================================*/
#include <iostream>

using namespace std;

int m;
int sum;

long y=0;
int* a;

int fun1(int x, int num, int left)
{
    int i;
    if (num >= m-1)
    {
        a[num]=left;
        for (i=0; i<m; i++)
            cout<<a[i]+1<<" ";
        cout<<endl;
        y++;
        return 0;
    }
    int count=x;
    while(1)
    {
        int nn=m-1-num;
        if ((left-count)/nn >= count)
        {
            a[num]=count;
            fun1(count, num+1, left-count);
            count++;
        }
        else break;
    }
    return 0;
}
int main()
{
    cout<<"请输入苹果数目: ";
    cin>>sum;
    cout<<"请输入箱子数: ";
    cin>>m;
    a=new int[m];
    y=0;
    fun1(0, 0, sum-m);
    cout<<"放法总数目为:"<<y<<endl;
    int bb; 
    cin>>bb;
}

回复列表 (共102个回复)

41 楼

直接 用数学公式算一下就可以了 ,
呵呵,
1000!÷(10!×(1000-10)!)=

42 楼

直接 用数学公式算一下就可以了 ,
呵呵,
1000!÷(10!×(1000-10)!)=

43 楼

晕。。。。都不认真想想就乱弄一个所谓的公式啊。。。
楼上的想想11个苹果的时候你的“公式”算出多少,如果不是1就肯定错了

44 楼

这种题很好啊,

45 楼

我看了43楼雨中飞燕的话后想到一点东西,

但事先声明,我是过场的,我不用C/C++
我只会QB,我只是说说楼上给我的提示而得出我的想法

因为这只是一个组合问题(不分顺序的)
我姑且把它看作一个降序处理,以便不分顺序,(箱子是一样的)

全是1,这是一种放法.
然后后面9个1不变,只变最前面一个1,有多少种变化?
(1-991),1,1,1,1......共991种放法,这应该没错吧?
然后排第二位的变成2呢?前面的不能比它小,也得从2开始,又有多少种变化呢?
(2-990),2,1,1,1......共989种放法,然后开始递减,等差是2
(3-989),3,1,1,1......共987.........
...............
496,496,1,1,1........共1种放法

归纳一下,算到第二位的时候,(后面8条1)
f(2)=E(991+989+987+.......+1)

然后计算到第三位......
f(3)=f(2)+E(988+986+......2)+E(985+..+1)+E(982+...)+......+E(1)
f(4)=f(2)+f(3)+E(........)

得以下比较直观一点的 VB 代码,但没有算出结果:
Dim sum, A(10), S(10), m, n, p
Sub moz()
m = 1000
n = 10
p = m \ n
sum = 0
S(0) = 0
For i = 1 To n
    A(i) = 1
    S(i) = S(i - 1) + A(i)
Next

Do Until A(1) > p
    r = m - S(9) - A(9) + 1
    If r > 0 Then
        sum = sum + r
    End If
    addap 9
    If A(6) = A(7) And A(7) = A(8) And A(8) = A(9) And A(9) = A(10) Then
       Debug.Print sum; A(10); A(9); A(8); A(7); A(6); A(5); A(4); A(3); A(2); A(1)
    End If
Loop
End Sub
Sub addap(k)
    If A(k) < (m - S(k - 1)) / (n - k + 1) Then
        r = A(k) + 1
        For i = k To n
            A(i) = r
            S(i) = S(i - 1) + A(i)
        Next
    Else
       addap (k - 1)
    End If
End Sub

运行过就知道计算原理了,需要优化一下.第二次改良,速度有改进,但计算过程仍需要改:
Dim sum, A(10), S(10), m, n, p
Sub moz()
m = 1000
n = 10
p = m \ n
sum = 0
S(0) = 0
For i = 1 To n
    A(i) = 1
    S(i) = S(i - 1) + A(i)
Next

Do Until A(1) > p
    For A(8) = A(7) To ((m - S(7)) / 3)
        r = m - S(8) - A(8) - A(8) + 1
        If r Mod 2 = 0 Then
            x = (r + 2) * r / 4
        Else
            x = (r + 1) * (r + 1) / 4
        End If
        sum = sum + x
    Next
    addap 7
    Debug.Print sum; A(10); A(9); A(8); A(7); A(6); A(5); A(4); A(3); A(2); A(1)
Loop
End Sub
Sub addap(k)
    If A(k) < (m - S(k - 1)) / (n - k + 1) Then
        r = A(k) + 1
        For i = k To n
            A(i) = r
            S(i) = S(i - 1) + A(i)
        Next
    Else
       addap (k - 1)
    End If
End Sub

再次优化计算过程为以下代码,很奇怪的,我自己都难以弄明白:
Dim sum, A(10), S(10), m, n, p, B(1000)
Sub moz()
m = 1000
n = 10
p = m \ n
sum = 0
S(0) = 0
For i = 1 To n
    A(i) = 1
    S(i) = S(i - 1) + A(i)
Next

For i1 = 990 To 1 Step -9
    For i2 = i1 To 1 Step -8
        For i3 = i2 To 1 Step -7
            For i4 = i3 To 1 Step -6
                For i5 = i4 To 1 Step -5
                    For i6 = i5 To 1 Step -4
                        For i7 = i6 To 1 Step -3
                            sumsum i7
Next i7, i6, i5, i4, i3, i2, i1
Debug.Print sum
End Sub
Sub sumsum(y)
If B(y) = 0 Then
        If y Mod 2 = 0 Then
            x = (y + 2) * y / 4
        Else
            x = (y + 1) * (y + 1) / 4
        End If
        B(y) = x
End If
sum = sum + B(y)
End Sub
结果还没有出来,希望最后能弄到结果,并出现高手来验算一下好了.

46 楼

归纳一下方法与计算过程,把程序修改成这个样子应该是正解了,可惜计算还是太慢.
S = 0
For i1 = 991 To 1 Step -10
 For i2 = i1 To 1 Step -9
  For i3 = i2 To 1 Step -8
   For i4 = i3 To 1 Step -7
    For i5 = i4 To 1 Step -6
     For i6 = i5 To 1 Step -5
      For i7 = i6 To 1 Step -4
       For i8 = i7 To 1 Step -3
        For i9 = i8 To 1 Step -2
         S = S + i9
Next i9, i8, i7, i6, i5, i4, i3, i2, i1
要找高手约分一下.

47 楼

偶的代码和楼上你的代码的计算原理是一样的(详见28楼)
用了递归,所以没有N层循环
但速度比你的快很多,主要是加了保存计算记录,这样下次碰到相同的环境的时候就不用再重复算了

当然,如果用组合数学里的整数拆分的知识来做的话就最快了

48 楼

[quote]

有谁能说说这个公式的由来吗?  :)

c(x,1)=1;
c(x,n)=c(x,n-1)+c(x-n,n-1)+c(x-2*n,n-1)+...c(x-i*n,n-1)+...+c(x%n,n-1);[/quote]
呵呵,这个公式很好理解拉,你把n个箱子按里面的苹果数排好序,假设从小到大排
则c(x-i*n,n-1)就是第一个的箱子(最少的)里有i个苹果的所有组合,等价于x-i*n在后面9个箱子里随便放的所有组合,(每个箱子都减去i个苹果组合数不变)

燕子的做法跟这个有点类似,只不过我的着眼点是最少的箱子里的苹果数而已

49 楼

其实我也改过,
但用EXCEL一个晚上都还有三重循环没算,所以没贴上来

Dim B(1000)
s = 0
For i1 = 991 To 1 Step -10
 For i2 = i1 To 1 Step -9
  For i3 = i2 To 1 Step -8
   For i4 = i3 To 1 Step -7
    For i5 = i4 To 1 Step -6
     For i6 = i5 To 1 Step -5
        Debug.Print i8; i7; i6; i5; i4; i3; i2; i1, s
      For i7 = i6 To 1 Step -4
       For i8 = i7 To 1 Step -3
        If B(i8) = 0 Then B(i8) = ((i8 + 1) ^ 2) \ 4
        s = s + B(i8)
Next i8, i7, i6, i5, i4, i3, i2, i1

然后我又听说你要用递归,
那我也来一个不是递归的递归.
但我实在对 C 的书写不在行,所以只能用BASIC代码,希望能看得明白,
(虽然运行没问题,但看上去就连我自己都是莫名其妙的)
不过间接寻址的确要比直接数来得慢一点点.

Sub moz()
Dim B(1000), F(10)
s = 0
i = 10
F(i) = 991
Do Until i > 10
    If i = 3 Then
        If B(F(i)) = 0 Then B(F(i)) = ((F(i) + 1) ^ 2) \ 4
        s = s + B(F(i))
        Do
            F(i) = F(i) - i
            If F(i) < 1 Then i = i + 1 Else Exit Do
        Loop
    Else
        i = i - 1
        F(i) = F(i + 1)
    End If
Loop
End Sub

过场的目的是想学学什么叫算法.呵呵,请各位观众别乱扔鸡蛋番茄

50 楼

好大的数啊886745696653253(用的int64)
读作“八百八十六万七千四百五十六亿九千六百六十五万三千二百五十三”(没读错吧。要是money多好啊:)

我来回复

您尚未登录,请登录后再回复。点此登录或注册