贪心算法

几乎所有题都应用到了排序,sort,min,*min_element

找出最快/慢,最大/小(一般先解决最不好解决的,即:最大和最慢)

 

  1. 把普遍进行排序
  2. 用个别的最优解映射出普遍的最优解

3.比如先考虑最大的(活动选择),先考虑最慢的(过河),或者用两者的普遍性规律来解题(区域覆盖)

(30条消息) 从零开始学贪心算法_houjingyi233的博客-CSDN博客_贪心算法

贪⼼算法⼀般分为如下四步:

1.将问题分解为若⼲个⼦问题

2.找出适合的贪⼼策略

3.求解每⼀个⼦问题的最优解

4.将局部最优解堆叠成全局最优解

 

1.活动选择问题

 这是《算法导论》上的例子,也是一个非常经典的问题。有n个需要在同一天使用同一个教室的活动a1,a2,…,an,教室同一时刻只能由一个活动使用。每个活动ai都有一个开始时间si和结束时间fi 。一旦被选择后,活动ai就占据半开时间区间[si,fi)。如果[si,fi]和[sj,fj]互不重叠,ai和aj两个活动就可以被安排在这一天。该问题就是要安排这些活动使得尽量多的活动能不冲突的举行。例如下图所示的活动集合S,其中各项活动按照结束时间单调递增排序。

局部最优解:最小的终点值进行排序,再对应起点的值

#include<bits/stdc++.h> 
using namespace std;
int n;
struct node
{
    int start;
    int end;
}act[1000];
bool cmp(node a,node b)
{
    return a.end<b.end;
}
int tx()
{
    int i=1,num=1;
    for(int j=2;j<=n;j++)
    {
        if(act[i].end<=act[j].start)
        {
            i=j;
            num++;
        }
    }
    return num;
}
int main()
{
       cin>>n;
       for(int i=1;i<=n;i++)
       {
           cin>>act[i].start>>act[i].end;
       }
       sort(act+1,act+n+1,cmp);
       int ans=tx();
       cout<<ans;
       return 0;
}

2.找钱

局部最优解:从大到小依次比较看看money是否大于value[i];

#include<bits/stdc++.h>
using namespace std;
int value[7]={1,2,5,10,20,50,100};
int Count[7]={3,0,2,1,0,3,5};
int solve(int money)
{
    int num=0;
    for(int i=6;i>=0;i--)
    {
        int c=min(money/value[i],Count[i]);//太强了
        money=money-c*value[i];
        num=num+c;
    }
            if(money>0)
        return -1;
        else return num;
}
int main()
{
    int money;
    cin>>money;
    int ans=solve(money);
    cout<<ans;
    return 0;
 } 

3.再论背包问题

只讨论了比例

#include<bits/stdc++.h>
using namespace std;
const int N=5;
void bili(float M,float w[],float v[],float x[])
{
    int i; 
    for(i=0;i<N;i++)
    {
        if(M>w[i])
        {
            x[i]=1;
            M=M-w[i];
        }
        else break;
    }
    if(i<N) x[i]=M/w[i];
}
int main()
{
    float M=50;
    float w[]={0,10,30,20,5};//从小到大排好序 
    float v[]={0,200,400,100,10};
    float x[N]={0};
    bili(M,w,v,x);
    for(int i=0;i<N;i++)
    {
        cout<<x[i]<<" ";
    }
    return 0;
 } 

4.分机调度

max_element、min_element用法详解

min_element 和 max_element

头文件#include<algorithm>

作用:返回容器中最小值和最大值的指针。max_element(first,end,cmp);其中cmp为可选择参数!

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int main() {
    int a[4]={1,2,3,4};
    vector<int> v={1,2,3,4}; 
    int m1=*max_element(a,a+4);
    int m2=*min_element(v.begin(),v.end());
    printf("%d %d",m1,m2);
    return 0;
}
max_element返回指定容器或数组范围[begin,end)内的最大值的迭代器或指针;
min_element返回指定容器或数组范围[begin,end)内的最小值的迭代器或指针;
注意返回的是迭代器或指针哈~,不是直接返回值。
#include<bits/stdc++.h>
using namespace std;
int speed[1000];
int w[1000];
int m,n;
bool cmp(int x,int y)
{
    return x>y;
}
void solve()
{
    for(int i=0;i<n;i++)
    {
        *min_element(w,w+m)+=speed[i];
    }
    cout<<*max_element(w,w+m)<<endl;
}
int main()
{
    cin>>n>>m;
    memset(speed,0,sizeof(speed));
    memset(w,0,sizeof(w));
    for(int i=0;i<n;i++)
    {
        cin>>speed[i];
    }
    sort(speed,speed+n,cmp); 
    solve();
    return 0;
}

5.小船过河

只要n>3那每次的任务都是:把最速度(speed)最慢的两个人送过去,并且保证最快的回来,有两种方法,每次都讨论哪一种更快。

#include<bits/stdc++.h>
using namespace std; 
int n,sum=0;
int speed[1000];
bool cmp(int x,int y)
{
    return x<y;
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    cin>>speed[i];
    sort(speed,speed+n,cmp);
    while(n>3)
    {
        sum+=min(speed[1]+speed[0]+speed[n-1]+speed[1],speed[n-1]+speed[0]+speed[n-2]+speed[0]);
        n-=2; 
    }
    if(n==3)
    sum+=speed[0]+speed[1]+speed[2];
    if(n==2)
    sum+=speed[1];
    if(n==1)
    sum+=speed[0];
    cout<<sum<<endl;
    return 0;
}

6.区间覆盖问题

把问题转化为区间问题,找到可以覆盖小岛的一个范围区间

局部最优解:依照左端带从小到大排序,查看下一个区间的情况:相交(point[i].x1>s的左端点&&point[i].x2>s),包含(point[i].x2<s),不相交也不包含(point[i].x1>s)从而分类讨论。

#include<bits/stdc++.h>
using namespace std;
int n,d;
int x,y;
double t;
struct node
{
    double x1,x2;
}point[1000];
bool cmp(struct node a1,struct node a2)
{
    return a1.x1<a2.x1;
}
int main()
{
    while(cin>>n>>d)
    {
        if(n==0&&d==0)
        break;
        int num=1;
        for(int i=0;i<n;i++)
        {
            cin>>x>>y;
            if(y>d)
            {
                num=-1;
                break;
            }
            t=sqrt(d*d-y*y);
            point[i].x1=x-t;
            point[i].x2=x+t;
        }
        if(num!=-1)
        {
            sort(point,point+n,cmp);
            double s=point[0].x2;
            for(int i=1;i<n;i++)
            {
                if(s>point[i].x2)
                {
                    s=point[i].x2;
                }
                if(s<point[i].x1)
                {
                    num++;
                    s=point[i].x2;
                }
            }
        }
        cout<<num<<endl;
     } 
 } 

简单的对以前在word中的算法笔记进行整理,自用,参考标注不完整,侵删

posted @ 2022-04-03 21:02  格蕾  阅读(57)  评论(0)    收藏  举报