贪心算法

                                                         贪心算法


 

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解 [1]  。

 

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择。也就是说,不从整体最优上加以考虑,做出的只是在某种意义上的局部最优解 [1]  。-------------------------------------------百度百科

使用条件

编辑
利用贪心法求解的问题应具备如下2个特征
1、贪心选择性质
一个问题的整体最优解可通过一系列局部的最优解的选择达到,并且每次的选择可以依赖以前作出的选择,但不依赖于后面要作出的选择。这就是贪心选择性质。对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解
2、最优子结构性质
当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用贪心法求解的关键所在。在实际应用中,至于什么问题具有什么样的贪心选择性质是不确定的,需要具体问题具体分析 [4]  
直接来一道例题

P1223 排队接水

题目描述

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

输入格式

第一行为一个整数 n。

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

输出格式

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

输入输出样例

输入 #1
10
56 12 1 99 1000 234 33 55 99 812
输出 #1
3 2 7 8 1 4 9 6 10 5
291.90

说明/提示

n1000,ti106,不保证 t_iti 不重复。

当 t_iti 重复时,按照输入顺序即可(sort 是可以的)                                   来自洛谷

要想使等待时间最短,就应该让时间短的人先接,这是小学的算术题,我们直接上代码。
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 struct kd{                
 6     long long h,t;            //声明一个结构体 
 7 };
 8 kd a[10000];
 9 bool cmp(kd x,kd y)
10 {
11     return x.t<y.t;            // 声明排序函数 
12 }
13 int main()
14 {
15     int n;
16     double s,c=0;
17     cin>>n;
18     for(int i=1;i<=n;i++)
19     {
20         cin>>a[i].t;
21         a[i].h=i;
22     }
23     sort(a+1,a+1+n,cmp);    //排序 
24     for(int i=1;i<=n;i++)
25     {
26         cout<<a[i].h<<" ";  //输出提水的编号 
27         s+=c;                //总时间=这个人等待的时间+前面人等待的总时间; 
28         c+=a[i].t;            //下一个人等待的时间= 这个人等待的时间+这
29                             //个人接水的时间
30     }
31     cout<<endl;
32     s/=n;    
33     printf("%.2lf",s);        
34 }

 需要注意一点,等待时间是不包括自己接水的时间的。鬼知道这段时间跑哪去了

一开始写了五六遍代码,样例输出一直是532.00,心态直接崩了

 

再来一道

P1803 凌乱的yyy / 线段覆盖

题目背景

快 noip 了,yyy 很紧张!

题目描述

现在各大 oj 上有 nn 个比赛,每个比赛的开始、结束的时间点是知道的。

yyy 认为,参加越多的比赛,noip 就能考的越好(假的)。

所以,他想知道他最多能参加几个比赛。

由于 yyy 是蒟蒻,如果要参加一个比赛必须善始善终,而且不能同时参加 22 个及以上的比赛。

输入格式

第一行是一个整数 nn ,接下来 nn 行每行是 22 个整数 a_{i},b_{i}ai,bi ( a_{i}<b_{i}ai<bi ),表示比赛开始、结束的时间。

输出格式

一个整数最多参加的比赛数目。

输入输出样例

输入 #1
3
0 2
2 4
1 3
输出 #1
2

一开始拿到题,感到无从下手。
仔细想一想,既然不考虑比赛长短,那是不是结束时间越早越好呢?
这是显然的,在不与上一次会议冲突的情况下,当然是结束时间越早越好。
这样,与下一次比赛就可以尽可能的减少冲突。也就是说,下一次可以选择的比赛更多
既然弄清楚了,那我们直接看代码。
#include<iostream>
#include<algorithm>
using namespace std;
struct meet{
    long long start,end;    
};
meet a[1000000];
bool cmp(meet x,meet y)
{
    return x.end<y.end;            //声明排序函数,按照结束时间由小到大 
}
int main()
{
    int n,s=1;
    cin>>n;
    for(int i=1;i<=n;i++)
    cin>>a[i].start>>a[i].end;
    sort(a+1,a+1+n,cmp);        //排序 
    int m=a[1].end,j=2;            //先参加结束最早的 ,结束时间为m 
    while(j<=n)                    //在总比赛数内进行,按照结束时间早晚循环 
        {
            if(a[j].start<m)    //如果冲突,看下一场比赛 
            j++;
            else{
                m=a[j].end;        //如果不冲突,总数+1,结束时间更新 
                j++;
                s++;
            }
        }
        cout<<s;
        return 0;             
}

 

 

 

 
posted @ 2021-02-04 11:53  S_Curry  阅读(258)  评论(0编辑  收藏  举报