• 20201206贪心法1总结


    贪心法1题目总结

    贪心法定义

    通过一个简单策略,来求得问题的最优解

    贪心法技巧

    1. 区间类的贪心,则可考虑左端点或右端点排序

    贪心习题(选自题单

    #10080. 删数问题

    思路

    循环(n)次,每次遍历一遍字符串,如一字符比后面字符大,则字符全部往前移一位(达到删除作用)

    注意
    1. 前导0的判断
    代码
    #include<bits/stdc++.h>
    using namespace std;
    string st;
    int n,len,p;
    bool flag;
    int main(){
        cin>>st>>n;
        len=st.size();
        while(n--){
            flag=false;
            for(int i=0;i<len-1;i++){
                if(st[i]>st[i+1]){
                    for(int j=i;j<len;j++)
                    	st[j]=st[j+1];
                    len--;
                    flag=true;
                    break;
                }
            }
            if(!flag)len--;
        }
        while(p<len-1&&st[p]=='0')p++;
        for(int i=p;i<len;i++)cout<<st[i];
    	return 0;
    }
    

    #10081. 活动选择

    思路

    首先,看到区间贪心,就想到排序!排完序,根据右端点,判断是否在一个区间的左端点内,如在则不选,反之就选

    代码
    #include<bits/stdc++.h>
    using namespace std;
    struct game{
        int begin;
        int end;
    }a[1010];
    int n,k,c;
    bool cmp(game a,game b){
    	return a.end<b.end;
    }
    int main(){
        cin>>n;
        for(int i=0;i<n;i++){
            cin>>a[i].begin>>a[i].end;
        }
        sort(a,a+n,cmp);
        int end=a[0].end;
        c=1;
        for(int i=1;i<n;i++){
            if(a[i].begin>=end){
                c++;
                end=a[i].end;
            }
        }
        cout<<c;
        return 0;
    }
    

    #10038. 最大整数

    思路

    这道题方法很简单,就是排序,可是怎么排序?这里有一个误区,会误以为直接将字符串按字典序从大到小排序就能AC,但是会有特例(如下图)。所以应根据连接起来后的字符串的字典序排序。

    代码
    /*
    ID: zhangbe5
    TASK: test
    LANG: C++
    */
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n;
    string s[30];
    bool cmp(string a,string b){
    	if(a+b>b+a)return true;
    	else return false;
    } 
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		cin>>s[i];
    	}
    	sort(s+1,s+n+1,cmp);
    	for(int i=1;i<=n;i++){
    		cout<<s[i];
    	}
    	return 0;
    }
    

    #10082. 整数区间

    思路

    恒古不变:看到区间想排序!右端点从小到大排序,判断是否在一个区间的范围内,是则答案数+1,反之继续找。

    另外,选在区间的端点上比选在区间内的一个点上的方案要更优,因为选在端点上方便判断是否重叠。

    代码
    /*
    ID: zhangbe5
    TASK: test
    LANG: C++
    */
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,ans,tmp;
    struct node{
    	int x,y;
    }a[10010];
    bool cmp(node a,node b){
    	return a.y<b.y;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d%d",&a[i].x,&a[i].y);
    	}
    	sort(a+1,a+n+1,cmp);
    	tmp=INT_MIN;
    	for(int i=1;i<=n;i++){
    		if(a[i].x<=tmp){
    			continue;
    		}else{
    			ans++;
    			tmp=a[i].y;
    		}
    	}
    	printf("%d",ans);
    	return 0;
    }
    

    #10045. 零件分组

    思路

    恒古不变:看到区间想排序。按照长度从小到大排序,因为本题要求两个变量同时不下降排列,则先让其中一个变量不下降排列,则只要看另一个变量划分组别即可。

    代码
    /*
    ID: zhangbe5
    TASK: test
    LANG: C++
    */
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n;
    struct node{
    	int l,w;
    }a[1010];
    int ans;
    bool f[1010];
    bool cmp(node a,node b){
    	return a.l<b.l||a.l==b.l&&a.w<b.w;
    } 
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d%d",&a[i].l,&a[i].w);
    	}
    	sort(a+1,a+n+1,cmp);
    	for(int i=1;i<=n;i++){
    		if(!f[i]){
    			int cur=a[i].w;
    			for(int j=i+1;j<=n;j++){
    				if(!f[j]){
    					if(cur<=a[j].w){
    						cur=a[j].w;
    						f[j]=true;
    					}
    				}
    			}
    			f[i]=true;
    			ans++;
    		}
    	}
    	printf("%d",ans);
    	return 0;
    }
    

    #10040. 纪念品组合

    思路

    将所有纪念品价格从小到大排序,一头一尾地选择符合要求的两个数(尽可能分更多的组),最后输出组数

    注意

    在算组数时,不要忘记算进单独一个数的情况

    代码
    /*
    ID: zhangbe5
    TASK: test
    LANG: C++
    */
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int w,n,a[30010],ans,l,r;
    bool f[30010];
    int main(){
    	scanf("%d%d",&w,&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	} 
    	sort(a+1,a+n+1);
    //	for(int i=1;i<=n;i++){
    //		if(!f[i]){
    //			for(int j=n;j>=i+1;j--){
    //				if(a[j]+a[i]<=w&&!f[j]){
    //					f[i]=f[j]=true;
    //					break;
    //				}
    //			}
    //			ans++;
    //		}
    //	}
    	l=1;
    	r=n;
    	while(l<r){
    		if(a[l]+a[r]<=w){
    			ans++;
    			l++;
    			r--;
    		}else{
    			r--;
    			ans++;
    		}
    	}
    	if(l==r)ans++;
    	printf("%d",ans);
    	return 0;
    }
    

    #10021. 均分纸牌

    思路

    计算出所有数的平均值,后根据平均值多到少分配(可以先“赊”一下,之后再还)

    代码
    /*
    ID: zhangbe5
    TASK: test
    LANG: C++
    */
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,a[110],ave,ans;
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		ave+=a[i];
    	}
    	ave/=n;
    	for(int i=1;i<=n;i++){
    		if(a[i]==ave){
    			continue;
    		}
    		ans++;
    		if(a[i]>ave){
    			a[i+1]+=a[i]-ave; 
    		}else{
    			a[i+1]-=(ave-a[i]);
    		}
    		a[i]=ave;
    	}
    	printf("%d",ans);
    	return 0;
    }
    

    #10043. 美元汇率

    思路

    每过去一天,计算一次若换算则能得到多少钱,不断找最多的,最后输出

    代码
    /*
    ID: zhangbe5
    TASK: test
    LANG: C++
    */
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    double d=100,m;
    int n;
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		double x;
    		cin>>x;
    		x/=100;
    		double dd=d;
    		d=max(d,m/x);
    		m=max(m,dd*x);
    	}
    	printf("%.2lf",d); 
    //	cout<<fixed<<setprecision(2)<<d;
    	return 0;
    }
    
    她透过我的血,看到了另一抹殷红
  • 相关阅读:
    LCA算法
    poj1364(差分约束系统)
    dij算法为什么不能处理负权,以及dij算法变种
    差分约束系统
    最短路专辑
    LightOJ1348 树链剖分
    FZU2082树链剖分
    HYSBZ1036 树链剖分
    poj3237 树链剖分 暴力
    poj2763 树链剖分(线段树)
  • 原文地址:https://www.cnblogs.com/zhangbeini/p/14093938.html
Copyright © 2020-2023  润新知