2.2一往直前贪心法

贪心

经典问题:取硬币

有1,5,10,50,100,500元硬币各c0,c1,c2,c3,c4,c5枚。现用这些硬币来支付A元,最少需要多少枚?

​ 首先能想到用暴力搜索,枚举完所有的情况即可求出其中最大者。

​ 但对于这类题目,我们通常会想到尽可能地使用大面额的硬币,就有了:在每个阶段,不断选取当前最优策略——贪心算法

#include<bits/stdc++.h>
//#include<iostream> 
using namespace std;
int main ()
{
	int a[6]={1,5,10,50,100,500};//硬币的面额
	int c[6],A ,ans=0;
	for(int i=0;i<6;i++)//读入每种面额硬币的个数
		cin>>c[i];
	cin>>A;
	for(int i=5;i>=0;i--)//尽可能选用大面额硬币
	{
		int t=min(A/a[i],c[i]);
		A-=t*a[i];
		ans+=t;
	}
	cout<<ans<<endl;
	return 0;
 } 

区间问题

n项工作,知道开始时间和结束时间,问最多能不重叠地参与多少项工作?

第一种想法,每次选取开始时间最早的。但有弊端可能持续时间太长反而造成项数减少。(×)

第二种想法,每次选取用时最短的。但可能开始时间太晚反而浪费。(×)

第三种想法,每次选取重叠次数最少。也可举出反例。(×)

第四种想法,每次选取结束时间最早的。结束时间越早,之后可选的工作也就越多。归纳法反证法能给出这个方法正确处理此问题的一个直观解释。(√)

以下是代码实现:

 //区间问题
#include<bits/stdc++.h>
#include<iostream> 
using namespace std;
const int maxn=1e5+5;
int s[maxn],t[maxn];	
pair<int ,int > a[maxn];//也可以用结构体的comp排序,但这个可以直接用sort更加方便
int main (){
	int n,x;
	cin>>n;
	for(int i=0;i<n;i++){cin>>x;a[i].second=x;}
	for(int i=0;i<n;i++){cin>>x;a[i].first=x;}//因为要选取结束时间最早的,即按第二个数组从小到大排列,所以将第二组存到first第一组存到second
	sort(a,a+n);//排序
	int ans=0,t=0;
	for(int i=0;i<n;i++)
	{
		if(t<a[i].second)//选取最靠近当前结束时间的开始时间(贪心思想)
		{
			ans++;t=a[i].first;//计数+标记当前结束时间
		}
	}
	cout<<ans<<endl;
	return 0;
} 

字典序最小问题(poj3617)

给定长度为n的字符串s,不断选取当前S两端较小的一个拼接到空字符串T中,求出T(即字符串T的字典序尽可能地小)

同样地不断选取每个时刻S两端(s与s反转字符)较小的一个即可

while(a<=b)
{
	bool left=false;
	for(int i=0;a+i<=b;++i)
	{
		if(S[a+i]<S[b-i])
			left=true;
		else if(S[a+i]>S[b-i])
			flag=false;
			

	}
	if(left)getchar(a++);
	else getchar(b--);

}
putchar('\n');

霍夫曼编码(Huffman)

根据使用频率来最大化节省字符(编码)的存储空间。

出现的频率越高,在树中的深度就越深。

是当码字长度为整数时最优的编码方案。

posted @ 2020-07-13 20:18  神奇周一  阅读(70)  评论(0编辑  收藏  举报