贪心法----选取当前最优策略

贪心的特点是选取当前最优策略,这也带来了缺点,当前的最优解不一定是最终的最优解。

1.硬币问题

         有1元、5元、10元、50元、100元、500元的硬币各C1、C5、C10、C50、C100、C500枚。现在要用这些硬币来支付A元,最少需要多少枚硬币?假定本题至少存在一种支付方案。

样例

输入

3 2 1 3 0 2 620

(C1、C5、........C500、A)

输出

6

(500+50*2+10+5*2)

提示:优先使用面值大的硬币

#include<iostream>
#include<algorithm>
using namespace std;
const int V[6]={1,5,10,50,100,500};
int C[6];
int A;
void solve(){
	int ans=0;
	for(int i=5;i>=0;i--){
		int t=min(A/V[i],C[i]);
		A-=t*V[i];
		ans+=t;
	}
	cout<<ans<<endl;
}
int main(){
	for(int i=0;i<6;i++) cin>>C[i];
	cin>>A;
	solve();
	return 0;
}

2.区间调度问题

          有n项工作,每项工作分别在si开始,ti结束。对每项工作,你都可以选择参加或不参加,但选择了参加某项工作就必须至始至终参加全程参与,即参与工作的时间段不能有重叠(即使开始的时间和结束的时间重叠都不行)。

样例:

输入

n=5

s={1,2,4,6,8}

T={3,5,7,9,10}

输出

3(选择工作1, 3, 5)

解题分析:

对这个问题,如果使用贪心算法的话,可能有以下几种考虑:

(1)、每次选取开始时间最早的;

(#)、每次选取结束时间最早的;

(2)、每次选取用时最短的;

(3)、在可选工作中,每次选取与最小可选工作有重叠的部分;

只有算法(#)是正确的。

对于(1):

对于(2):

对于(3):

具体证明如下:

 

数轴上有n个区间,选出最多的区间,使得这些区间不互相重叠。

算法:

将所有区间按右端点坐标从小到大排序,顺序处理每个区间。如果它与当前已选的所有区间都没有重叠,则选择该区间,否则不选。

证明:

显然,该算法最后选出的区间不互相重叠,下面证明所选出区间的数量是最多的。设fi为该算法所接受的第i个区间的右端点坐标,gi为某最优解中的第i个区间的右端点坐标。

命题1.1  当i>=1时,该算法所接受的第i个区间的右端点坐标fi<=某最优解中的第i个区间的右端点坐标gi。

该命题可以运用数学归纳法来证明。对于i=1,命题显然为真,因为算法第一个选择的区间拥有最小右端点坐标。令i>1,假定论断对i-1为真,即fi-1<=gi-1。则最优解的第i个可选区间所组成的集合包含于执行该算法时第i个可选区间所组成的集合;而当算法选择第i个区间时,选的是在可选区间中右端点坐标最小的一个,所以有fi<=gi。证毕。

设该算法选出了k个区间,而最优解选出了m个区间。

命题1.2  最优解选出的区间数量m=该算法选出的区间数量k。

假设m>k,根据命题1.1,有fk<=gk。由于m>k,必然存在某区间,在gk之后开始,故也在fk之后开始。而该算法一定不会在选了第k个区间后停止,还会选择更多的区间,产生矛盾。所以m<=k,又因为m是最优解选出区间个数,所以m=k。

综上所述,算法选出的区间是最优解。

#include<iostream>
#include<algorithm>
using namespace std;

const int MAX_N=1e5;
int N,S[MAX_N],T[MAX_N];
pair<int,int>itv[MAX_N];

void solve(){
	for(int i=0;i<N;i++){
		itv[i].first=T[i];
		itv[i].second=S[i];
	}
	sort(itv,itv+N);
	int ans=0,t=0;
	for(int i=0;i<N;i++){
		if(t<itv[i].second){
			ans++;
			t=itv[i].first;
		}
	}
	cout<<ans<<endl;
}
int main(){
	cin>>N;
	for(int i=0;i<N;i++) cin>>S[i];
	for(int i=0;i<N;i++) cin>>T[i];
	
	solve();
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乌药ice

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值