其他分享
首页 > 其他分享> > 贪心思想总结

贪心思想总结

作者:互联网

日期:2022年5月25日

注:本博客仅供参考


 

概念与思路

贪心算法是指在对某一问题求解时,总是作出当前情况下的最优选择。因此,贪心算法考虑的不是整个问题的最优解,算法得到的是在某一局部环境下的最优解。

贪心算法的一般思路为:

  1. 把要求解的问题分为若干个子问题;
  2. 对每个子问题求解,得到子问题的局部最优解;
  3. 把得到的局部最优解合为原来问题的一个解。

注意事项(尤为重要)

代码与应用

部分背包问题(P2240)

题目描述

阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有N(N≤100)堆金币,第i堆金币的总重量和总价值分别是 mi,vi(1≤mi,vi≤100)。阿里巴巴有一个承重量为T(T≤1000)的背包,但并不一定有办法将全部的金币都装进去。他想装走尽可能多价值的金币。所有金币都可以随意分割,分割完的金币重量价值比(也就是单位价格)不变。请问阿里巴巴最多可以拿走多少价值的金币?

输入格式

第一行两个整数 N,T。

接下来N行,每行两个整数 mi,vi

输出格式

一个实数表示答案,输出两位小数。

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=110;
 4 int n,t;
 5 struct node{
 6     int m;
 7     int v;
 8 };
 9 node a[N];
10 bool operator <(node a,node b){
11     return a.v*b.m>b.v*a.m;
12     /*用金币价值与金币质量的比值来比较不同金币的实际价值
14     return a.v*b.m>b.v*a.m的效果等同于return a.v/a.m>b.v/b.w,但由于在C++中“/”意为整除,所以需要使用其他方法代替除法*/
15 }
16 int main(){
17     scanf("%d%d",&n,&t);
18     for(int i=1;i<=n;++i)
19     {
20         scanf("%d%d",&a[i].m,&a[i].v);
21     }
22     sort(a+1,a+1+n);//重定义的的“<”会在这里用到
23     double ans=0;
24     for(int i=1;i<=n;++i)
25     {
26         if(a[i].m<=t)//当金币质量小于背包能容纳的剩余质量时,将这堆金币全部放进去
27         {
28             ans+=a[i].v;
29             t-=a[i].m;
30         }else{//当金币质量大于背包能容纳的剩余质量时,用这种金币将背包的剩余部分填满并结束循环
31             ans+=1.0*t*a[i].v/a[i].m;
32             break;
33         }
34     }
35     printf("%.2lf",ans);
36     return 0;
37 }         

排队接水(P1223)

题目描述

有n个人在一个水龙头前排队接水,假如每个人接水的时间为Ti,请编程找出这n个人排队的一种顺序,使得n个人的平均等待时间最小。

输入格式

第一行为一个整数n。

第二行n个整数,第i个整数Ti 表示第i个人的等待时间Ti

输出格式

输出文件有两行,第一行为一种平均时间最短的排队顺序;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1000100;
 4 int n;
 5 double ave=0;
 6 struct node{
 7     int t;
 8     int code;
 9 };
10 bool operator <(node a,node b){
11     return a.t<b.t;//升序排列
12 }
13 node T[N];
14 int main(){
15     scanf("%d",&n);
16     for(int i=1;i<=n;++i)
17     {
18         scanf("%d",&T[i].t);
19         T[i].code=i;
20     }
21     sort(T+1,T+1+n);
22     for(int i=1;i<=n;++i)
23     {
24         for(int j=0;j<i;++j)
25         {
26             ave+=T[j].t;
27         }
28         printf("%d ",T[i].code);
29     }
30     ave/=n;//平均等待时间为所有人需要等待的时间与人数的比值
31     printf("\n%.2lf",ave);
32     return 0;
33 }

均分纸牌(P1031)

题目描述

有NN堆纸牌,编号分别为 1,2,…,N。每堆上有若干张,但纸牌总数必为N的倍数。可以在任一堆上取若干张纸牌,然后移动。

移牌规则为:在编号为1堆上取的纸牌,只能移到编号为2的堆上;在编号为N的堆上取的纸牌,只能移到编号为N-1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。

现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。

例如N=4,4堆纸牌数分别为:

①9②8③17④6

移动3次可达到目的:

从 ③ 取4张牌放到 ④ (9,8,13,10)-> 从 ③ 取3张牌放到 ②(9,11,10,10)-> 从 ② 取1张牌放到①(10,10,10,10)。

输入格式

两行

第一行为:N(N堆纸牌,1≤N≤100)。

第二行为:A1,A2, … ,An​ (N堆纸牌,每堆纸牌初始数,1≤Ai≤10000)。

输出格式

一行:即所有堆均达到相等时的最少移动次数。

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=110;
 4 int n,a[N],ave=0,sum=0;
 5 int main(){
 6     scanf("%d",&n);
 7     for(int i=1;i<=n;++i)
 8     {
 9         scanf("%d",&a[i]);
10         ave+=a[i];
11     }
12     ave/=n;//纸牌平均数恒为定值
13     for(int i=1;i<=n;++i)
14     {
15         if(a[i]!=ave)//如果这堆纸牌不是平均值,向右边放a[i+1]-ave张纸牌
16         {
17             a[i+1]+=a[i]-ave;
18             ++sum;
19         }
20     }
21     printf("%d",sum);
22     return 0;
23 }

铺设道路(P5019)

题目描述

春春是一名道路工程师,负责铺设一条长度为n的道路。

铺设道路的主要工作是填平下陷的地表。整段道路可以看作是n块首尾相连的区域,一开始,第i块区域下陷的深度为di

春春每天可以选择一段连续区间[L,R],填充这段区间中的每块区域,让其下陷深度减少1。在选择区间时,需要保证,区间内的每块区域在填充前下陷深度均不为0。

春春希望你能帮他设计一种方案,可以在最短的时间内将整段道路的下陷深度都变为0。

输入格式

输入文件包含两行,第一行包含一个整数n,表示道路的长度。 第二行包含n个整数,相邻两数间用一个空格隔开,第i个整数为di

输出格式

输出文件仅包含一个整数,即最少需要多少天才能完成任务。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=100100;
 4 int n,d[N],sum=0;
 5 int main(){
 6     scanf("%d",&n);
 7     for(int i=1;i<=n;++i)
 8     {
 9         scanf("%d",&d[i]);
10     }
11     sum+=d[1];
12     for(int i=2;i<=n;++i)
13     {
14         if(d[i]>d[i-1])
15         {
16             sum+=d[i]-d[i-1];//如果后面大于前面,则共有d[i]-d[i-1]层需要单独填掉(小于的部分可以和前面一起填掉)
17         }
18     }
19     printf("%d",sum);
20     return 0;
21 }

 

标签:总结,10,思想,纸牌,int,金币,算法,贪心
来源: https://www.cnblogs.com/PlayerSS05/p/16308823.html