【2018.2.26算法总结#分治】
分治法:1.将一个问题分成许多小问题,求解小问题。2.将小问题重新组合成一个问题。
例子:
-
排队购票
问题描述:一场球赛开始前,售票工作正在紧张进行中。每张球票为50元,有m+n个人排队等待购票,其中有m 个人手持50元的钞票,另外n个人手持100元的钞票。求出这m+n个人排队购票,使售票处不至出现找不开钱的局面的不同排队种数 。(约定:开始售票时售票处没有零钱,拿同样面值钞票的人对换位置为同一种排队。)
问题分析:
令f(m,n)表示有m个人手持50元的钞票,n个人手持100元的钞票时共有的排除总数。 分以下3种情况来讨论。
- n=0:意味着排队购票的所有人手中拿的都是50元的钱币,注意到拿同样面值钞票的人对换位置为同一种排队,那么这m个人的排队总数为1,即f(m,0)=1。
- m<n:当m<n时,即购票的人中持50元的人数小于持100元的钞票,即使把m张50元的钞票都找出去,仍会出现找不开钱的局面,这时排队总数为0,即f(m,n)=0。
- 其它情况 第m+n个人手持100元的钞票,则在他之前的m+n-1个人中有m个人手持50元的钞票,有n-1个人手持100元的钞票,此种情况共有f(m,n-1)。 第m+n个人手持50元的钞票,则在他之前的m+n-1个人中有m-1个人手持50元的钞票,有n个人手持100元的钞票,此种情况共有f(m-1,n)。
由加法原理得到f(m,n)的递归关系: f(m,n)=f(m,n-1)+f(m-1,n)
初始条件: 当m<n时,f(m,n)=0 当n=0时,f(m,n)=1
long f(int j,int i) { long y; if(i==0) y=1; else if(j<i) y=0; // 确定初始条件 else y=f(j-1,i)+f(j,i-1); // 实施递归 return(y); }
2.未名湖边的烦恼
问题描述
每年冬天,北大未名湖上都是滑冰的好地方。北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰鞋都不剩。
每天早上,租鞋窗口都会排起长龙,假设有还鞋的m个,有需要租鞋的n个。现在的问题是,这些人有多少种排法,可以避免出现体育组没有冰鞋可租的尴尬场面。(两个同样需求的人(比如都是租鞋或都是还鞋)交换位置是同一种排法)
每天早上,租鞋窗口都会排起长龙,假设有还鞋的m个,有需要租鞋的n个。现在的问题是,这些人有多少种排法,可以避免出现体育组没有冰鞋可租的尴尬场面。(两个同样需求的人(比如都是租鞋或都是还鞋)交换位置是同一种排法)
输入格式
两个整数,表示m和n
输出格式
一个整数,表示队伍的排法的方案数。
样例输入
3 2
样例输出
5
数据规模和约定
m,n∈[0,18]
分析:如同第一个例子一样,先考虑最初始两种条件,再考虑最后一个人的情况。
1 #include<iostream> 2 #include<stdio.h> 3 using namespace std; 4 int f(int m,int n){ 5 int y; 6 if(n==0)//没有人借鞋子 7 y=1; 8 else if(m<n)//借鞋子的人多 9 y=0; 10 else 11 y=f(m-1,n)+f(m,n-1);//最后一个人之前有多少个人可以退鞋 12 return y; 13 } 14 int main(){ 15 int m,n; 16 cin>>m; 17 cin>>n; 18 cout<<f(m,n)<<endl; 19 20 return 0; 21 }