国科大算法概论课后作业

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)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值