问题:
有一座金字塔,从上到下,第一层有一个杯子、第二层有两个杯子,依次类推。对杯子进行编号,有如下的形状:
1
2 3
4 5 6
每个杯子的容量为C升,从塔顶倒下L升水,当1号杯子满了之后,会等量溢出到2号和3号杯子。当2号和3号满了,2号溢出到4号和5号,3号溢出到5号和6号,注意5号接受来自两个杯子的水。依次类推。给定C和L,请问,第n杯里有多少水。
from @陈利人
分析:
此题没有想到好的方法,只想到模拟(或者算DP),
f[leveli, index] 表示第leveli层的第index个酒杯共收到的水的量。那么:
f[leveli, index] = ( f[leveli-1, index-1] – C ) / 2 + ( f[leveli-1, index] – C ) / 2 。
这里 f[leveli-1, index-1] – C、 f[leveli-1, index] – C 不小于0, 否则相应项为0。
实现:使用hashMap做备忘录,进行DP。
代码:时间复杂度O(n), 空间复杂度O(n)
double getFlow(int C, int leveli, int index, unordered_map<int, double> &hashMap){
if(index < 0 || index > leveli)
return 0;
int n = (leveli + 1) * leveli / 2 + index;//总的索引
auto p = hashMap.find(n);
if(p != hashMap.end())
return p->second;
double leftFlow = getFlow(C, leveli - 1, index -1, hashMap);
double rightFlow = getFlow(C, leveli - 1, index, hashMap);
return hashMap[n] = (leftFlow >= C ? (leftFlow - C) / 2 : 0)
+ (rightFlow >= C ? (rightFlow - C) / 2 : 0);
}
int main() {
int L = 10;
int C = 5;
int n = 1;//n值从0开始,表示总的索引
int leveli = 0, sum = 0;
while(sum + (leveli + 1) < n + 1) //初始化所在层次:leveli
sum += leveli++ + 1;
int index = n - (leveli + 1) * leveli / 2; //计算所在行的索引
unordered_map<int, double> hashMap;
hashMap[0] = L;//初始化Map
double flow = getFlow(C, leveli, index, hashMap);
cout << (flow > C ? C : flow) << endl;
}
补充:杨辉三角知识
n次的二项式系数对应杨辉三角形的n+1行。
例如:在(a+b)^2=a^2+2ab+b^2中,2次的二项式正好对应杨辉三角形第3行系数1 2 1。
性质: