贪心上机训练题解

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

第一题 数列极差

贪心策略:

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

#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<<"
";
	}
//	for(int j=1;j<=n;j++){
//			cout<<y[j].a<<" ";
//	}
	printf("%d",sum);
	return 0;
} 

第六题 糖果传递

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

数学:

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
";
    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