主题:[原创]解金山公司面试题
if007
[专家分:650] 发布于 2007-03-10 03:31:00
/*************************************
文件名: 解金山公司面试题
创建人: 陈泽丹
创建时间: 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;
}
最后更新于:2007-03-10 03:37:00
回复列表 (共102个回复)
41 楼
xylgg [专家分:800] 发布于 2007-03-15 21:02:00
直接 用数学公式算一下就可以了 ,
呵呵,
1000!÷(10!×(1000-10)!)=
42 楼
xylgg [专家分:800] 发布于 2007-03-15 21:03:00
直接 用数学公式算一下就可以了 ,
呵呵,
1000!÷(10!×(1000-10)!)=
43 楼
雨中飞燕 [专家分:18980] 发布于 2007-03-15 23:53:00
晕。。。。都不认真想想就乱弄一个所谓的公式啊。。。
楼上的想想11个苹果的时候你的“公式”算出多少,如果不是1就肯定错了
44 楼
hackhou [专家分:60] 发布于 2007-03-16 01:51:00
这种题很好啊,
45 楼
moz [专家分:37620] 发布于 2007-03-16 03:47:00
我看了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 楼
moz [专家分:37620] 发布于 2007-03-16 04:07:00
归纳一下方法与计算过程,把程序修改成这个样子应该是正解了,可惜计算还是太慢.
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 楼
雨中飞燕 [专家分:18980] 发布于 2007-03-16 12:29:00
偶的代码和楼上你的代码的计算原理是一样的(详见28楼)
用了递归,所以没有N层循环
但速度比你的快很多,主要是加了保存计算记录,这样下次碰到相同的环境的时候就不用再重复算了
当然,如果用组合数学里的整数拆分的知识来做的话就最快了
48 楼
forjane [专家分:5670] 发布于 2007-03-16 13:45:00
[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 楼
moz [专家分:37620] 发布于 2007-03-16 13:57:00
其实我也改过,
但用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 楼
ttuurr [专家分:70] 发布于 2007-03-16 15:32:00
好大的数啊886745696653253(用的int64)
读作“八百八十六万七千四百五十六亿九千六百六十五万三千二百五十三”(没读错吧。要是money多好啊:)
我来回复