1. 求解下述递归关系的渐进界
a. T(n) = 9T(n/3) + n
b. T(n) =T(2n/3) +1
c. T(n) = 3T(n/4) + nlgn
解:
2.算法设计
假定我们开着一辆车,从城市A到城市B,沿途经过n个苹果市场,包括城市A和城市B的苹果市场,编号为1~n。在市场i, 1≤i≤n,从顾客的角度看,每斤苹果的买入价B[i]和卖出价S[i]都已知(单位是元)。下图给出了一个n=6的情况。
现在,我们计划找一个市场i买苹果,然后找一个市场j≥i卖苹果,并使得赚的钱尽量多(如果不赚钱的话,则使亏的钱尽量少)。假设车不允许向回开,并且只做一次买卖。例如上面的例子中,最佳方案是在市场4买入,在市场6卖出,每斤可赚差价为7-2=5元。请设计一个分治算法找出买入的市场i和卖出的市场j并使得利润最大或亏损最少,并分析问题的复杂度。
(1)设计算法如下:
首先,很容易想到暴力求解:
for B[i]
for S[j] //此处(j>=i)
ans = max(S[j]-B[j]);
显然,暴力求解的时间复杂度为O(n²)。
下面,根据题目要求,使用分治算法求解:
(1)算法设计
int findMaximumProfit(vector<int> buy,vector<int> sell,int b,int s,int &b_pos,int &s_pos){
//buy 是买入价数组 sell 是卖出价数组,[b,s]是购买区间,b_pos 是购买点,s_pos 是售卖点
//返回值是 利润最大或亏损最少的数
//第一步、确定 “底” 的实现
if(b==s) return sell[s]-buy[b];
//第二步、确定 “分” 的实现,按照每次[1/2]进行分片
int mid = (b+s)>>1;
L = findMaximumProfit(buy,sell,b,mid,lb_pos,ls_pos);//查找左半部分最优解
R = findMaximumProfit(buy,sell,mid+1,s,rb_pos,rs_pos);//查找右半部分最优解
T = max(sell[s]-buy[b]);//循环查找[b,s]区间最大利润点 为t
//第三步、确定 “合” 的实现,根据不同值,进行更新购买点和售出点
if(L>R && L>T){
(b_pos ,s_pos) = (lb_pos,ls_pos)
}else if(R>L && R>T){
(b_pos ,s_pos) = (rb_pos,rs_pos)
}else {
(b_pos ,s_pos) = (t, min(max(rs_pos,ls_pos),s));
}
return max(L,R,T); //返回 max(左L、右R、全部T) 三部分的最大值
}
(2)算法C++实现如下:
int findMaximumProfit(vector<int> buy,vector<int> sell,int b,int s,int &b_pos,int &s_pos){
//buy 是买入价数组 sell 是卖出价数组,[b,s]是购买区间,b_pos 是购买点,s_pos 是售卖点
//返回值是 利润最大或亏损最少的数
if(b==s) return sell[s]-buy[b];
int mid = (b+s)>>1;
int lb_pos = b_pos,ls_pos = min(mid,s_pos);
int rb_pos = max(mid+1,b_pos),rs_pos = s_pos;
int L = findMaximumProfit(buy,sell,b,mid,lb_pos,ls_pos);//查找左半部分最优解
//cout<<"L区间:["<<b+1<<" "<<mid+1<<"] max= "<<L<<endl;
int R = findMaximumProfit(buy,sell,mid+1,s,rb_pos,rs_pos);//查找右半部分最优解
//cout<<"R区间:["<<mid+2<<" "<<s+1<<"] max= "<<R<<endl;
int t = b;//t 用来保存最大利润的购买点
int T = sell[s]-buy[b];for(int i=b+1;i<=s;++i){if(sell[s]-buy[i]>T){T = sell[s]-buy[i];t = i;}}//循环查找最大利润点
//cout<<"T区间:["<<b+1<<" "<<s+1<<"] max= "<<T<<endl;
//更新购买点和售出点
if(L>R && L>T){
b_pos = lb_pos; s_pos = ls_pos;
}else if(R>L && R>T){
b_pos = rb_pos; s_pos = rs_pos;
}else {
b_pos = t; s_pos = min(max(rs_pos,ls_pos),s);
}
//cout<<"###区间:["<<b+1<<" "<<s+1<<"]"<<endl;
//cout<<"购买点:"<<b_pos+1<<" 出售点 :"<<s_pos+1<<" 最大利润: "<<max(L,max(R,T))<<endl;
return max(L,max(R,T)); //返回 max(左L、右R、全部T) 三部分的最大值
}
int main(){
while(true){
int n,t;
cin>>n;
vector<int> buy,sell;
for(int i=0;i<n;++i){cin>>t;buy.push_back(t);}
for(int i=0;i<n;++i){cin>>t;sell.push_back(t);}
int b_pos=0,s_pos=n-1;
int ans = find(buy,sell,0,n-1,b_pos,s_pos);
cout<<"最终的 "<<"购买点:"<<b_pos+1<<" 出售点 :"<<s_pos+1<<" 最大利润: "<<ans<<endl;
}
return 0;
}
(3)程序计算结果如下:
(2)问题的复杂度
本问题采用分治算法解决,每次分片都为【1/2】,故总的
T(n) = 2T( floor(n/2)) + n = O(nlgn)
所以算法的时间复杂度为O(nlgn)