一、由整数1,2,3.....组成了一颗无限大的满二叉树,给出2个正整数,代表二叉树中的节点,求出这2个节点最近的公共祖先
int common(int x , int y){
if(x = y) return x;
else if(x > y)
return common(x/2,y);
else
return common(x,y/2);
}
二、求逆波兰表达式
逆波兰表达式是一种把运算符前置的算术表达式,例如(2 + 3) *4的逆波兰表示法为*+234。
double exp(){
char a[10];
scanf("%s",a);
switch(a[0]){
case '+' : return exp() + exp();
case '-' : return exp() - exp();
case '*' : return exp() * exp();
case '/' : return exp() / exp();
default:return atof(a);
}
}
将逆波兰表达式转换成常规表达式输出,可以包含多余的括号
void exp(){
char a[10];
scanf("%s",a);
switch(a[0]){
case '+' :
cout << "(" ;
exp();
cout << "+" ;
exp();
cout << ")";
break;
case '-' :
cout << "(" ;
exp();
cout << "-" ;
exp();
cout << ")";
break;
case '*' :
exp();
cout << "*" ;
exp();
break;
case '/' :
exp();
cout << "/" ;
exp();
break;
default : cout << atof(a) ;
}
}
三、放苹果
把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问有多少种不同的分法?ps:5,1,1和1,5,1是同一种分法。
(1):当盘子数为1的时候,只有一种放法就是把所有苹果放到一个盘子里。
(2):当苹果数为1的时候,也只有一种放法,注意题目中说明,盘子之间并无顺序,所以不管这个苹果放在哪个盘子里,结果都算一个。
(3):当m<n时,因为此时最多只能放到m个盘子中去(一个里放一个),实际上就相当于把m个苹果放到m个盘子里一样,也就是f(m,m);
(4):当m==n时,此时分两种情况讨论,一种是一个盘子里放一个,只是一种,第二种是,至少有一个盘子里不放苹果这就相当于是f(m,m-1);
(5):当m>n时,也分两种情况讨论,一种是至少有一个盘子里不放苹果,这样子就相当于f(m,n-1),第二种是,先取出n个苹果一个盘子里放一个,再将剩下的m-n个苹果放到n个盘子里去,即f(m-n,n);
int f(int m,int n){
if(m == 0 || n == 1)
return 1;
if(m < n)
return f(m,m);
return f(m - n,n) + f(m,n - 1);
}
可以用记忆化搜索,把f(m,n)换成f[m][n];
这种做法可以统计总的放法,但是要得到每一种放法,还是要搜索+剪枝
搜索就不说了,主要是剪枝提高了效率,当剩下的苹果平均放到剩余的盘子中的时候,每个盘子分的的苹果数目小于前一个盘子放置的苹果数目,这样就不满足我们给的要求ai-1<ai,所以加上条件
((m - w)/(n - k)) >= s[k - 1]
void dfs(int k, int w){ //初始k=1,w=0;k表示现在已经用的盘子,w表示已经放了几个苹果
if(k == n){ //当最后一个盘子被放置苹果的时候我们进行判断
if(m - w >= s[k - 1]){
s[k] = m - w;
int i;
for(i = 1;i < n;i++)
cout << s[i] << " ";
cout << s[i] << endl;
}
return;
}
for(int i = 0;i <= m;i++){
if(i >= s[k - 1] && ((m - w)/(n - k)) >= s[k - 1] ){ //如果当前放置的苹果个数大于前一个盘子继续放置,后半部分是剪枝
s[k] = i;
w = w + i;
k = k + 1;
dfs(k,w);
w = w - i;
k = k - 1;
}
}
}