一道百度面试题---200元的组合方式有多少
/*************************************************
设计者:cslave
版本说明:本代码免费用于商用,拷贝,转移,使用,但是
有本代码导致的问题,本人概不负责。
设计时间:2012.7.6
分发原则:遵守GNU规范。如有错误麻烦请通知本人谢谢。
**************************************************/
/*********************************************
题目描述:
人民币有 1元 2元 5元 10元 20元 50 元 100元 这几种币值.
问:给定200元,求出有多少种币值组合方式. 币种可重复,比如,200张1元的算一种方式.
解法:
依次设 1元 2元 5元 10元 20元 50 元 100元张数为 x,y,z,m,n,p,q
则有
x+2y+5z+10m+20n+50p+100q=200 其中
0=<x<=200
0=<y=<100
0=<z=<40
0=<m=<20
0=<n=<10
0=<p=<4
0=<q=<2
可以采用for循环迭代输出的方案,但是太朴素。也可以采用
递归方案:
F(n)=F(n-1)+F(n-2)+F(n-5)+F(n-10)+F(n-20)+F(n-50)+F(n-100)
当然也可以采用自底向上的方案来输出,但是耗时都比较长
我们可以采用一种新的方案:
x+2y+5z+10m+20n+50p+100q=200 可以分治为
q=0; x+2y+5z+10m+20n+50p=200 等价于 2y+5z+10m+20n+50p<=200
q=1; x+2y+5z+10m+20n+50p=100 等价于 2y+5z+10m+20n+50p<=100
q=2: x+2y+5z+10m+20n+50p=0 只有一种选法
当q=0时
设10m+20n+50p=10k,则 2y+5z<=200-10k (0<=k<=20)
同时 2n+5p<=k;
所以
Sum=0;
for(k=0;k<=20;k++)
Sum=Count(2y+5z<=200-10k)* Count(2n+5p<=k);
当q=1时
设10m+20n+50p=10k,则 2y+5z<=100-10k (0<=k<=10)
同时 2n+5p<=k;
所以
Sum=0;
for(k=0;k<=10;k++)
Sum=Count(2y+5z<=100-10k)* Count(2n+5p<=k);
当q=2时
仅有一种方案。
Count来自于格点三角形公式,格点三角形公式是 S=E/2+I-1,
其中,E表示边界上格点数目,I表示内部的格点数目,S为格点三角形面积。
边界上格点数目为两个直角边的点数。
将格点三角形面积公式重写为
S+E/2=E/2+E/2+I-1 即为 I+E=S+E/2+1;
下面让我们想想 ,I+E为格点三角形的内部和边界顶点,他们是
满足2n+5p<=k条件的n和p的对应正整数解。
让我们通过公式计算 Count(2n+5p<=k)
对于k%10==0的情况。
E=8*M/10=4M/5 (列举2n+5p<=10想想就明白了)
S=(1/2)*(M/2)*(M/5)=M*M/20
所以I+E=S+1+E/2=M*M/20+1+2M/5
对于k%10!=0的情况 ,也就是k%10>0
2n+5p=10t+h (1 <=h <=9)。(t> =1)
当h为奇数时,p必为奇数 ,解的数目为不超过[(10t+h)/5]的所含奇数的数目
当h为偶数时,p必为偶数,解的数目为不超过[(10t+h)/5]的所含偶数的数目
[(10t+h)/5]值本身可能是2t或者2t+1;
当h=1,3时候 解的个数为t (考虑下 0 ,1,2,...,2t)
当h=2,4,5,6,7,8,9时,解的个数为t+1 (考虑下 0 ,1,2,...,2t,2t+1)
所以当h=1,2,3.。。。,9的时候,对应的解个数为
h 解个数
0 M*M/20+1+2M/5
1 t +M*M/20+1+2M/5
2 2t+1 +M*M/20+1+2M/5
3 3t+1 +M*M/20+1+2M/5
4 4t+2 +M*M/20+1+2M/5
5 5t+3 +M*M/20+1+2M/5
6 6t+4 +M*M/20+1+2M/5
7 7t+5 +M*M/20+1+2M/5
8 8t+6 +M*M/20+1+2M/5
9 9t+7 +M*M/20+1+2M/5
好了 到这里不解释了,写代码吧。
*********************************************/
1 #include "stdafx.h" 2 #include <iostream> 3 using namespace std; 4 5 int ComposeMoney(int Cycle) 6 { 7 if(Cycle%100!=0) 8 throw exception("Cycle Is not Timesof 100!\n"); 9 int Sum=0; 10 int cycle=Cycle/10; 11 int Para1,Para2; 12 int Temp; 13 int t,h,k; 14 for(k=0;k<=cycle;k++) 15 { 16 Para1=Cycle-10*k; 17 Para2=k; 18 t=Para2/10;h=Para2%10; 19 Temp=5*t*t+1+4*t; 20 if(1<=h&&h<=2) Temp+=h*t+h-1; 21 else if(h>=3) Temp+=h*t+h-2; 22 Sum+=Temp* (Para1*Para1/20+1+2*Para1/5); 23 24 } 25 return Sum; 26 } 27 28 29 void Test() 30 { 31 try 32 { 33 int Sum=ComposeMoney(200)+ComposeMoney(100)+1; 34 cout<<Sum<<endl; 35 } 36 catch(exception& e) 37 {cout<<e.what();} 38 } 39 40 41 int _tmain(int argc, _TCHAR* argv[]) 42 { 43 Test(); 44 return 0; 45 }
如果有什么错误的地方,麻烦周知我,谢谢。