算法篇之贪心法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Mind_programmonkey/article/details/88766775

                                         算法篇之贪心法

                                                                                                            -----细说贪心法(细说不是胡说)

 

目录

  算法篇之贪心法

前言

一、什么是贪心法

1.什么是贪心算法

2.基本思路

3.算法实现

二、常见的贪心问题

1.背包问题

2.会场安排问题

3.非洲小孩

4.心急的C小加


前言

        最近因为复试的原因,对几个算法进行了一定程度的了解,这一篇将详细讲述一下贪心,让大家浅显易懂的明白贪心。

一、什么是贪心法

1.什么是贪心算法

       贪心算法(又称贪婪算法)是指,在对问题求解时,总是作出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所作出的仅是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题它能产生整体最优解或者是整体最优解的近似解。

2.基本思路

(1)建立数学模型来描述问题

(2)把求解的问题分成若干个子问题

(3)对每一子问题求解,得到子问题的局部最优解

(4)把子问题的解局部最优解合成原来解问题的一个解

3.算法实现

(1)从问题的某个初始解出发;

(2)采用循环语句,当可以向求解目标前进一步时,就根据局部最优策略,得到一个部分解,缩小问题的范围或规模;

(3)将所有部分解综合起来,得到问题的最终解。

 

       总的来说,贪心算法将问题的求解过程看作是一系列选择,每次选择一个输入,每次选择都是当前状态下的最好选择(局部最优解)。每作一次选择后,所求问题会简化为一个规模更小的子问题。从而通过每一步的最优解逐步达到整体的最优解。

       贪心算法的示意图

       其中:

               红箭头表示当前最优决策;蓝箭头表示其他决策;小球表示当前状态。

二、常见的贪心问题

1.背包问题

题目描述:

现在有很多物品(它们是可以分割的),我们知道它们每个物品的单位重量的价值v和重量w(1<=v,w<=10);如果给你一个背包它能容纳的重量为m(10<=m<=20),你所要做的就是把物品装到背包里,使背包里的物品的价值总和最大。

输入描述:

第一行输入一个正整数n(1<=n<=5),表示有n组测试数据;
随后有n测试数据,每组测试数据的第一行有两个正整数s,m(1<=s<=10);s表示有s个物品。接下来的s行每行有两个正整数v,w。

输出描述:

输出每组测试数据中背包内的物品的价值和,每次输出占一行。

样例输入:

1
3 15
5 10
2 8
3 9

样例输出:

65

分析:

        目标函数:总价值最大

        约束条件是装入的物品总重量不超过背包容量

               a.根据贪心的策略,每次挑选价值最大的物品装入背包,得到的结果是否最优?

               b.每次挑选所占空间最小的物品装入是否能得到最优解?

               c.每次选取单位容量价值最大,成为解本题的策略。

        根据以上的分析我们就可以得到解决本题的策略。即单位容量最大的物品。

#include<iostream>
#include<algorithm>
#define maxsize 10
using namespace std;
struct Node{
	int v;
	int w;
};
Node map[maxsize];
int cmp(Node mapa,Node mapb)
{
	return mapa.v>mapb.v;
}
int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		int i,s,m,sum=0;
		cin>>s>>m;
		for(i=0;i<s;i++)
			cin>>map[i].v>>map[i].w;
		sort(map,map+s,cmp);
		for(i=0;i<s;i++)
		{
			if(m>=map[i].w)
			{
				m-=map[i].w;
				sum+=map[i].w*map[i].v;
			}
			else
			{
				sum+=m*map[i].v;
				break;
			}
		}
		cout<<sum<<endl;
	}
	return 0;
} 

2.会场安排问题

题目描述:

学校的小礼堂每天都会有许多活动,有时间这些活动的计划时间会发生冲突,需要选择出一些活动进行举办。小刘的工作就是安排学校小礼堂的活动,每个时间最多安排一个活动。现在小刘有一些活动计划的时间表,他想尽可能的安排更多的活动,请问他该如何安排。

输入描述:

第一行是一个整型数m(m<100)表示共有m组测试数据。
每组测试数据的第一行是一个整数n(1<n<10000)表示该测试数据共有n个活动。
随后的n行,每行有两个正整数Bi,Ei(0<=Bi,Ei<10000),分别表示第i个活动的起始与结束时间(Bi<=Ei)

输出描述:

对于每一组输入,输出最多能够安排的活动数量。
每组的输出占一行

样例输入:

2
2
1 10
10 11
3
1 10
10 11
11 20

样例输出:

1
2

        分析:活动安排问题要求安排一系列争用某一公共资源的活动。用贪心算法可提供一个简单、漂亮的方法,使尽可能多的活动能兼容的使用公共资源,设有n个活动的集合{0,1,2,..,n-1},其中每个活动都要求使用同一资源,如会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间strati和一个结束时间endi,且starti<endi.如选择了活动i,则它在半开时间区间[starti,endi)内占用资源。若区间[starti,endi)与区间[startj,endj)不相交,称活动i与活动j时相容的。也就是说,当startj>=endi或starti>=endj时,活动i与活动j相容。活动安排问题就是在所给的活动集合中选出最多的不相容活动。

#include<iostream>
#include<algorithm>
#define maxsize 10000
using namespace std;
struct ac{
	int start;
	int end;
};
int cmp(ac aca,ac acb)
{
	return aca.end<acb.end;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int i,j,n,sum=1,time;
		ac acs[maxsize];
		cin>>n;
		for(i=0;i<n;i++)
			cin>>acs[i].start>>acs[i].end;
		sort(acs,acs+n,cmp);
		time=acs[0].end;
		for(i=1;i<n;i++)
		{
			if(acs[i].start>time)
			{
				sum++;
				time=acs[i].end;
			}
		}
		cout<<sum<<endl;
	}	
} 

3.非洲小孩

          解题思路类似于上述两题,这里就不在赘述了。

题目描述:

家住非洲的小孩,都很黑。为什么呢?
第一,他们地处热带,太阳辐射严重。
第二,他们不经常洗澡。(常年缺水,怎么洗澡。)
现在,在一个非洲部落里,他们只有一个地方洗澡,并且,洗澡时间很短,瞬间有木有!!(这也是没有的办法,缺水啊!!)
每个小孩有一个时间段能够洗澡。并且,他们是可以一起洗的(不管你是男孩是女孩)。
那么,什么时间洗澡,谁应该来洗,由谁决定的呢?那必然是他们伟大的“澡”神啊。“澡”神有一个时间表,记录着该部落的小孩,什么时候段可以洗澡。现在,“澡”神要问你,一天内,他需要最少开启和关闭多少次洗澡的水龙头呢?因为,开启和关闭一次水龙头是非常的费力气的,即便,这也是瞬间完成的。

输入描述:

多组数据
第一行一个0<n<=100。
接下来n行,每行一个时间段。H1H1:M1M1-H2H2:M2M2,24小时制。
保证该时间段是在一天之内的。但是,不保证,H1H1:M1M1先于H2H2:M2M2。

输出描述:

题目描述,“澡”神最少需要开启和关闭多少次水龙头呢?

样例输入:

1
00:12-12:12
3
00:12-13:14
13:13-18:00
17:00-19:14

样例输出:

1
2

提示:

Ps:开启和关闭为一次

#include<iostream>
#include<stdlib.h>
#include<algorithm>
#define maxsize 100
using namespace std;
struct water{
	int start;
	int end;
};
int cmp(water a,water b)
{
	return a.end<b.end;
}
int main()
{
	int n;
	while(cin>>n)
	{
		int i=0,h1,m1,h2,m2;
		water a[maxsize];
		for(i=0;i<n;i++)
		{
			scanf("%d:%d-%d:%d",&h1,&m1,&h2,&m2);
			m1+=h1*60;
			m2+=h2*60;
			if(m1>m2)
				swap(m1,m2);
			a[i].start=m1;
			a[i].end=m2;
		}	
		sort(a,a+n,cmp);
		int ans=1,flag=a[0].end;
		for(i=1;i<n;i++)
		{
			if(a[i].start>flag)
			{
				ans++;
				flag=a[i].end;
			}
		}
		cout<<ans<<endl;
	}	
	return 0;
} 

4.心急的C小加

题目描述:

C小加有一些木棒,它们的长度和质量都已经知道,需要一个机器处理这些木棒,机器开启的时候需要耗费一个单位的时间,如果第i+1个木棒的重量和长度都大于等于第i个处理的木棒,那么将不会耗费时间,否则需要消耗一个单位的时间。因为急着去约会,C小加想在最短的时间内把木棒处理完,你能告诉他应该怎样做吗?
 

输入描述:

第一行是一个整数T(1<T<1500),表示输入数据一共有T组。
每组测试数据的第一行是一个整数N(1<=N<=5000),表示有N个木棒。接下来的一行分别输入N个木棒的L,W(0 < L ,W <= 10000),用一个空格隔开,分别表示木棒的长度和质量。

输出描述:

处理这些木棒的最短时间。

样例输入:

3 
5 
4 9 5 2 2 1 3 5 1 4 
3 
2 2 1 1 2 2 
3 
1 3 2 2 3 1 

样例输出:

2
1
3
#include<iostream>
#include<algorithm>
#define maxsize 5000
using namespace std;
struct node{
	int l;
	int w;
};
int cmp(node a,node b)
{
	if(a.l==b.l)
		return a.w<b.w;
	return a.l<b.l;
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int i,j,n;
		cin>>n;
		node wood[maxsize];
		int visit[maxsize],count=0;
		for(i=0;i<n;i++)
		{
			cin>>wood[i].l>>wood[i].w;
			visit[i]=0;
		}
		sort(wood,wood+n,cmp);
		for(i=0;i<n;i++)
		{
			if(visit[i]==0)
			{
				count++;
				visit[i]=1;
				node t=wood[i];
				for(j=i+1;j<n;j++)
				{
					if(wood[j].w>=t.w&&visit[j]==0)
					{
						t=wood[j];
						visit[j]=1;
					}
				}
			}
		}
		cout<<count<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Mind_programmonkey/article/details/88766775
今日推荐