贪心上机训练题解

终于我把贪心的上机训练做完了,现在就把这六道题说一下

第一题 数列极差

贪心策略:

从小到大排序,每次擦掉最大的两个数,然后剩下的就是最小的
从小到大排序,每次擦掉最小的两个数,然后剩下的就是最大的
稍微提示一下,我们每次都要擦掉最小的两个数,所以每一遍都要拍一遍序
并且:千万别排成别的数组
知道了这样的贪心策略,程序也很好写出来

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,a[50050],b[50050],c[50050];
int minn,maxx;
    void ask_min(){
        for(int i=1;i<n;i++){
            b[i+1]=b[i]*b[i+1]+1;
            sort(b+1,b+n+1);
        }
        minn=b[n];
    }
    void ask_max(){
        for(int i=n;i>1;i--){
            
            c[i-1]=c[i]*c[i-1]+1;
            sort(c+1,c+i);
        }
        maxx=c[1];
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            b[i]=a[i];
            c[i]=a[i];
        }
        sort(c+1,c+n+1);
        sort(b+1,b+n+1);
        ask_min();
        ask_max();
        printf("%d",minn-maxx);
        return 0;
    }

第二题 数列分段

贪心策略:

每段尽可能接近m
code:

#include<bits/stdc++.h>
using namespace std;
int m,n,sum,ans;
int a[100010];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
        sum+=a[i];
        if(sum==m){
            ans+=1;
            sum=0;
            continue;
        }
        if(sum>m){
            ans+=1;
            i--;
            sum=0;
            continue;
        }
        if(sum<m&&i==n){
            ans+=1;break;
        }
    }
    printf("%d",ans);
    return 0;
}

第三题 线段

例题一...
code:

#include<bits/stdc++.h>
using namespace std;
int n,record,ans;
struct Node{
    int b,e,w;
}a[1000010];
bool cmp(Node x,Node y){
    if(x.e==y.e) return x.w<y.w;
    return x.e<y.e;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i].b,&a[i].e);
        a[i].w=a[i].e-a[i].b;
    }
    sort(a+1,a+n+1,cmp); 
    for(int i=1;i<=n;i++){
        if(record<=a[i].b){
            record=a[i].e;
            ans++;
        }
    }
    cout<<ans;
    return 0;
} 

第四题 家庭作业

例题五...

但是

我把代码复制过去竟然没过,于是稍微优化了一下
最开始,我打了个快读,反而更慢了(难道说字符串还没有scanf优秀?)
所以就开始从贪心实现这方面思考,怎么才能优化
搜索有剪枝,剪掉多余的,无用的循环、搜索
我就让贪心也剪掉多余的循环
用一个dis来储存现在究竟到了哪一天(前面的天数都不能再做作业了)
这样当后面的再有x[i].a < dis 的就continue了
减少了进入下一个循环的次数
于是就成功的过了这道题
code:

#include<bits/stdc++.h>
using namespace std;
int n,ans,dis;
struct Node{
    int a,b;
}x[1000005];
bool cmp(Node xx,Node yy){
    if(xx.b==yy.b) return xx.a<yy.a;
    return xx.b>yy.b;
}
#define rg register
inline int read(){
    rg int s=0,f=0;
    rg char ch=getchar();
    while(!isdigit(ch)) f|=(ch=='-'),ch=getchar();
    while(isdigit(ch)) s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
    return f?-s:s;
}
bool fk[1000005];
int main(){
//    scanf("%d",&n);
    n=read();
    for(rg int i=1;i<=n;i=-~i){
        x[i].a=read();
        x[i].b=read();
    }
    sort(x+1,x+n+1,cmp);
    for(rg int i=1;i<=n;i=-~i){
        if(x[i].a<dis) continue;
        int bj=1;
        for(rg int j=x[i].a;j;--j){
            if(!fk[j]){
                fk[j]=1;
                bj=0;
                ans+=x[i].b;
                break;
            }
        }
        if(bj==1) dis=x[i].a;
    }
    printf("%d",ans);    
    return 0;
}

第五题 钓鱼

这道题一开始我是真心不会,问的本机房的一位神犇,他说这是一道DP
但是DP我还没学,而且书上给的上机训练的的确确说这道题是贪心。
转过头去,问另一位大佬,他用了几分钟时间就想出了贪心思路
直接交,立马AC
所以,贪心还是需要多做题,这样才能立刻想出来。

贪心思路:

我们可以把每次要去的最远的鱼塘模拟一遍,之后就知道了到每个鱼塘所需的走路时间
如此之后,它的走路消耗便可以不算了
题目就变成了:有n个鱼塘,到每个的距离都是0
怎样在每个鱼塘钓鱼...
这样它的贪心策略也就变成了:每次看哪一个鱼塘里的与最多。
code:

#include<bits/stdc++.h>
using namespace std;
int n,h,t[105],ans,c[105],sum;
struct Node{
    int a,m;
}x[105];
struct Nod{
    int a,m;
}y[105];
bool cmp(Nod x,Nod y){
    return x.a>y.a;
}
int main(){
    scanf("%d%d",&n,&h);
    h*=12;
    for(int i=1;i<=n;i++) scanf("%d",&x[i].a);
    for(int i=1;i<=n;i++) scanf("%d",&x[i].m);
    for(int i=2;i<=n;i++) scanf("%d",&t[i]);
    t[1]=0;
    for(int i=1;i<=n;i++){
        h-=t[i];
        ans=0;
        for(int j=1;j<=i;j++){ 
            y[j].a=x[j].a;
            y[j].m=x[j].m;
        }
        for(int j=1;j<=h;j++){
            sort(y+1,y+i+1,cmp);
            if(y[1].a<0) continue;
            ans+=y[1].a;
            y[1].a-=y[1].m;
        }
        if(ans>sum) sum=ans;
//      cout<<ans<<"\n";
    }
//  for(int j=1;j<=n;j++){
//          cout<<y[j].a<<" ";
//  }
    printf("%d",sum);
    return 0;
} 

第六题 糖果传递

看这题第一眼:这不均分纸牌吗?
再多看几眼,这题咋整?

数学:

o_rr.png

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
long long sum,n,need,ans;
long long y[1000005],a[1000050],x[1000050];
int main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        sum+=a[i];
    }
    need=sum/n;
    sum=a[1];
    for(int i=2;i<=n;i++){
        y[i]=-((i-1)*need-sum);
        sum+=a[i];
    }
    sort(y+1,y+n+1);
    memset(a,0,sizeof(a));
    x[1]=y[(n+1)/2];
//    cout<<x[1]<<"   sdf;laj\n";
    for(int i=1;i<=n;i++){
//      cout<<x[i]<<" ";
        a[i]=x[1]-y[i];
//        cout<<a[i]<<" ";
    }
//    for(int i=1;i<=n;i++) cout<<x[i]<<" ";
    for(int i=1;i<=n;i++) ans+=abs(a[i]);
    printf("%lld",ans);
    return 0;    
}

只有六道练习题,所以还没完全掌握,之后一定要多刷题!

转载于:https://www.cnblogs.com/fashpoint/p/11318971.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值