贪心类问题总结

区间选点

给定 N N N 个闭区间 [ a i , b i ] [a_{i},b_{i}] [ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点,输出选择的点的最小数量(位于区间端点上的点也算作区间内)

思路:

将每个区间按照右端点从小到大进行排序,从前往后枚举区间,最右边界值ed初始化为无穷小,之后和区间左端点比较,不断更新即可

代码:

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;

struct Range{
    
    
    int l, r;
    bool operator< (const Range &W)const{
    
    
        return r < W.r;//按r从小到大排序
    }
}range[N];

int main(){
    
    
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ) scanf("%d%d", &range[i].l, &range[i].r);
    sort(range, range + n);
    int res = 0, ed = -2e9;
    for (int i = 0; i < n; i ++ )
        if (range[i].l > ed){
    
    
            res ++ ;
            ed = range[i].r;
        }
    printf("%d\n", res);
    return 0;
}

活动安排

传送门
在这里插入图片描述
思路:

和上一题类似,唯一的不同就是代码部分if (range[i].l > ed)要改变为if (range[i].l >= ed),因为活动是左闭右开的,左右端点可以重合,代表2个活动可以依次发生,不像上一题,区间上点如果重合,则会亏一些

种树

传送门
在这里插入图片描述
思路:

和上一题类似,一样的排序,如果当前区间的树不够的话,就在区间右端点种树

WA的代码:

#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=3e4+5;
bool b[N];
struct tree{
    
    
    int l,r,num;
    bool operator <(tree const &t1)const{
    
    
        return r<t1.r;
    }
}a[N];

int n,m;
int main(){
    
    
    ll res=0;
    cin>>n>>m;
    f(i,0,m){
    
    
        scanf("%d %d %d",&a[i].l,&a[i].r,&a[i].num);
    }
    sort(a,a+m);
    f(i,0,m){
    
    
        int cnt=0;
        ff(j,a[i].l,a[i].r){
    
    
            if(b[j])cnt++;
        }
        if(cnt>=a[i].num)continue;
        for(int j=a[i].r,p=0;p<(a[i].num-cnt);j--,p++){
    
    
            b[j]=1;res++;
        }
    }
    cout<<res<<endl;
    return 0;
}

之后发现WA的原因是在重复地方种树了,因为虽然是右区间从小到大排的序,但是左区间不确定,所以说区间树的分布可能是中间有很多树,但区间的两边没有树,所以要设一个标记数组,重复的树不再标记,可以看下面的图:
在这里插入图片描述
AC代码:

#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=3e4+5;
bool b[N];
struct tree{
    
    
    int l,r,num;
    bool operator <(tree const &t1)const{
    
    
        return r<t1.r;
    }
}a[N];

int n,m;
int main(){
    
    
    ll res=0;
    cin>>n>>m;
    f(i,0,m){
    
    
        scanf("%d %d %d",&a[i].l,&a[i].r,&a[i].num);
    }
    sort(a,a+m);
    f(i,0,m){
    
    
        int cnt=0;
        ff(j,a[i].l,a[i].r){
    
    
            if(b[j])cnt++;
        }
        if(cnt>=a[i].num)continue;
        for(int j=a[i].r;j>=a[i].l;j--){
    
    
            if(!b[j]){
    
    
            	b[j]=1;
				res++;
				cnt++;
				if(cnt>=a[i].num)break;
            }
        }
    }
    cout<<res<<endl;
    return 0;
}

喷水装置

传送门
在这里插入图片描述
思路:

将区间按左端点从小到大排序,从左向右依次处理每个区间。每次选择覆盖点st的区间中右端点坐标最大的一个(设为ed),并将st更新为ed,直到浇灌完草坪,或喷头用完为止

代码:

#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=2e4+5;
struct st{
    
    
    double l,r;
    bool operator<(st const &t1)const{
    
    
        return l<t1.l;
    }
}a[N];
int t;

int main(){
    
    
    cin>>t;
    while(t--){
    
    
        int n;
        double L,W;
        scanf("%d %lf %lf",&n,&L,&W);
        W/=2;
        double p,r;
        int cnt=0;
        f(i,0,n){
    
    
            scanf("%lf %lf",&p,&r);
            //取等的时候就包含那一个点,可以要。。
            if(r<W)continue;
            double d=sqrt(r*r-W*W);
            a[cnt].l=p-d,a[cnt].r=p+d;
            cnt++;
        }
        sort(a,a+cnt);
        int flag=0,pos=0;
        double ed=0;
        int res=0;
        while(ed < L){
    
    
            res++;
            //该写成double的别写成int
            double st=ed;
            for(; a[pos].l <= st && pos < cnt; pos++){
    
    
                if(a[pos].r>ed)ed=a[pos].r;
            }
            if(ed>=L)break;
            if(st==ed){
    
    
                flag=1;
                cout<<-1<<endl;
                break;
            }
        }
        if(!flag)cout<<res<<endl;
    }
    return 0;
}

加工生产调度

传送门

样例解释:
在这里插入图片描述

推荐一篇题解:【贪心】加工生产调度(双机调度贪心问题)

WA代码:
在这里插入图片描述

#include<bits/stdc++.h>
typedef long long ll;
#define debug(x) cout<<#x<<" : "<<x<<endl;
using namespace std;

struct node{
    
    
    int id,a,b,flag;
}item[10010];

bool cmp(node x,node y){
    
    
    //整体分为2部分:先bi较大(ai<bi),再ai较大(ai>bi)
    if(x.flag!=y.flag)
        return x.flag<y.flag;
    //bi较大的里面,按ai较小排序
    if(x.flag==0)
        return x.a<y.a;
    //ai较大的里面,按bi较大排序
    else return x.b>y.b;
}

int main(){
    
    
    int n; scanf("%d",&n);
    for(int i=0;i<n;i++)scanf("%d",&item[i].a);
    for(int i=0;i<n;i++)scanf("%d",&item[i].b);
    for(int i=0;i<n;i++){
    
    
        item[i].id=i+1;
        item[i].flag=(item[i].a<item[i].b?0:1);
    }
    sort(item,item+n,cmp);
    ll A=0,B=0;
    for(int i=0;i<n;i++){
    
    
        A+=item[i].a;
        B=max(A,B)+item[i].b;
    }
    printf("%lld\n",B);
    for(int i=0;i<n;i++){
    
    
        if(i!=n-1)cout<<item[i].id<<" ";
        else cout<<item[i].id<<endl;
    }
}

不知道为啥QAQ,感觉很疑惑

推荐另一篇题解:【结论】加工生产调度

又得到了WA代码:
在这里插入图片描述

#include <bits/stdc++.h>
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
using namespace std;
//
const int N=10005;
int n,sum1=0,sum2=0,l=0,r;
int res[N],a[N],b[N];

struct st{
    
    
    int x,id;
    bool operator <(st const &t1)const{
    
    
        return x<t1.x;
    }
}num[N];

int main(){
    
    
    scanf("%d",&n);
    ff(i,1,n) cin>>a[i];
    ff(i,1,n) cin>>b[i];
    ff(i,1,n)
        num[i].id=i,num[i].x=min(a[i],b[i]);

    sort(num,num+n+1);

    r=n+1;

    ff(i,1,n){
    
    
        //对应博客里m==a,放前面
        if(num[i].x==a[num[i].id]) res[++l]=num[i].id;
        //对应博客里m==b,放后面
        else res[--r]=num[i].id;
    }

    ff(i,1,n){
    
    
        sum1+=a[res[i]];
        sum2=max(sum1,sum2)+b[res[i]];
    }

    cout<<sum2<<"\n";
    ff(i,1,n)
        cout << res[i] << " ";

    return 0;
}

AC代码:

把结构体sort排序改为手动排序:
在这里插入图片描述

for(int i=1;i<=n-1;i++)
    for(int j=i+1;j<=n;j++)
        if(num[i].x>num[j].x){
    
    
            swap(num[i].x,num[j].x);
            swap(num[i].id,num[j].id);
        }

稍微改一下结构体重载比较函数的代码,发现分数高了!
在这里插入图片描述

struct st{
    
    
    int x,id;
    bool operator <(st const &t1)const{
    
    
        return x<=t1.x;
    }
}num[N];

于是猜测题目出锅了(它缺少special judge哇

猜你喜欢

转载自blog.csdn.net/qq_45550375/article/details/119117181