1.贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
2.贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
一.背包问题
题意
有一个背包,背包容量是M。有n个物品,物品可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。
思路
代码
#include
#include
using namespace std;
typedef struct{
int w;
int v;
double avg;
}P;
bool cmp(P a,P b){
return a.avg>b.avg;
}
int main(){
P *p;
int n,i,m;//n 物品个数 m背包容量
while(cin>>n>>m){
p=new P[n];
for(i=0;i>p[i].w>>p[i].v;
p[i].avg=p[i].v/p[i].w*1.0;
}
sort(p,p+n,cmp);
int maxvalue=0;
for(i=0;i
二.活动安排问题
题意:
输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。
Sample Input
12
1 3
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
5 10
4 14
2 9
0
Sample Output
5
思路
要求看的节目数量最多,从而可使用贪心的算法尽可能多看,首先是将数据按照节目结束时间从小到大排序,越是结束时间早,越是可以屯出时间去看下一个节目,看完一个节目后,检查排序后相邻的下一个节目的start是否大于或者等于当前节目的end,如果大成立则下一个节目是下次准备看的节目,否则再往下继续找,直到满足条件为止
代码
#include
#include
#include
using namespace std;
struct time
{
int t1;
int t2;
}a[110];
int cmp(time a,time b)
{
if(a.t2==b.t2)
return a.t1>b.t1;
return a.t2>n)&&n!=0)
{
for(i=0; i>a[i].t1>>a[i].t2;
}
sort(a,a+n,cmp);
for(i=1,t=a[0].t2,s=1; i=t)
{
t=a[i].t2;
s++;
}
}
cout<
三.考虑卖商品截止日期求最大利润
题意:
超市里有n个产品要卖,每个产品都有一个截至时间dx(从开始卖时算起),只有在这个截至时间之前才能卖出并且获得率润dy。
有多个产品,所有可以有不同的卖出顺序,每卖一个产品要占用1个单位的时间,问最多能卖出多少利润。
Sample Input
4 50 2 10 1 20 2 30 1
7 20 1 2 1 10 3 100 2 8 2
5 20 50 10
Sample Output
80
185
思路:
先把所有产品按照利润从大到小排序,然后这个把这个放在截止日期那天卖出,并做好标记,如果截至日期那天已经有其他产品占用了,那么可以把这个产品卖出的时间往前推,直到找到可以卖的那一天并标记好。
假设一个产品a占用了一个日期后,那么如果下次又有一个产品b和产品a的截止日期是相同的,但是那个日期以被占用了,所以就要往前移动1天,那么就可以用并查集进行标记,在a占用了那个日期后,把a的截止日期指向前一个日期,这样的话,可以直接查找到他要占用到哪一个时间。
代码:
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=10005;
int visited[maxn]; //代表第i天是否有卖商品
struct node{
int p,d;
};
bool cmp(node a,node b){
return a.p>b.p;
}
int main()
{
int n;
while(~scanf("%d",&n)){
memset(visited,0,sizeof(visited));
node a[maxn]; //存商品
for(int i=0;i=1;j--){ //在截止日期之前卖出就行
if(visited[j])
continue;
visited[j]=1;
sum+=a[i].p;
break;
}
}
printf("%d\n",sum);
}
return 0;
}
四.区间覆盖问题
题意:
铺路问题。给出n段长度的起止位置,要求用长为l的木板铺路,最少用多少块木板可以铺完。
Sample Input
3 3
1 6
13 17
8 12
Sample Output
5
思路:
既然给出n个泥坑的起止位置,而且不重合,那么就按照开始的位置进行排序。
排序后从头开始铺木板。
代码:
#include
#include
#include
#include
#include
#define MAX 100000
using namespace std;
struct DIS
{
int s,e;
}dis[MAX];
bool cmp(DIS a,DIS b)
{
return a.s < b.s;
}
int main()
{
int n,l;
scanf("%d%d",&n,&l);
for (int i = 1; i <= n; i++)
{
scanf("%d%d",&dis[i].s,&dis[i].e);
}
sort(dis + 1, dis + 1 + n,cmp);
int sum = 0;//sum表示总共需要的木板
int length = 0;
for (int i = 1; i <= n; i++)
{
if (length >= dis[i].e)//如果当前长度大于泥坑的末端,则上一块木板可以铺完,continue;
continue;
length = max(dis[i].s,length);//否则看是否铺开新的泥坑。即比较当前长度和下一个泥坑开始的长度。
while (length < dis[i].e)//这里就是铺下一个泥坑,直到当前长度铺完当前长度的泥坑。
{
sum += 1;
length += l;
}
}
printf("%d\n",sum);
return 0;
}
五.多机调度问题
1.机器是完全相同的,不同的作业处理时间是独立的
题意:
n个作业组成的作业集,可由m台相同机器加工处理。要求给出一种作业调度方案,使所给的n个作业在尽可能短的时间内由m台机器加工处理完成。
思路:
作业不能拆分成更小的子作业;每个作业均可在任何一台机器上加工处理。 这个问题是NP完全问题,还没有有效的解法(求最优解),但是可以用贪心选择策略设计出较好的近似算法(求次优解)。当n<=m时,只要将作业时间区间分配给作业即可;当n>m时,首先将n个作业从大到小排序,然后依此顺序将作业分配给空闲的处理机。也就是说从剩下的作业中,选择需要处理时间最长的,把它分配给当前总累计需要工作时长最短的机器。
代码:
#include
#include
using namespace std;
int speed[10010];
int mintime[110];
bool cmp( const int &x,const int &y)
{
return x>y;
}
int main()
{
int n,m;
memset(speed,0,sizeof(speed));
memset(mintime,0,sizeof(mintime));
cin>>n>>m;
for(int i=0;i>speed[i];
sort(speed,speed+n,cmp);
for(int i=0;i