zoukankan      html  css  js  c++  java
  • 贪心算法

    贪心策略:总是考虑在当前状态下局部最优的策略,一定满足最优子结构,不断地把问题归纳为更小的相似地子问题

    拟阵:许多用贪心算法求解的问题,可以表示求带权拟阵的最大权独立子集问题

    最少硬币问题:

    给定面值,给定要付的钱,求最少需要多少硬币

    !如果面值为1、2、5或者1、2、4、8这种才可以用贪心计算,只有面值任一硬币面值都大于比它小的的和,才能计算

    //先排序 
    	int mon[10]={1,2,5};
    	int all;
    	cin>>all;
    	int num[10];
    	for(int i=0;i<3;i++){
    		num[i]=all/mon[i];
    		all=all-mon[i]*num[i];
    	}
    

    对于任意面值的求解:动态规划

     1、打印最少硬币组合

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    using namespace std;
    const int maxn=1010;
    const int INF=0x3fffffff;
    typedef long long LL;
    int money=251;
    int tot=5;
    int type[5]={1,5,10,25,50};
    int num[maxn];
    int path[maxn];
    void prin(int *path,int s){
    	while(s){
    		cout<<path[s]<<" ";
    		s-=path[s];
    	}
    }
    void sovle(){
    	for(int i=0;i<money;i++) num[i]=INF;
    	num[0]=0;
    	
    	for(int j=0;j<tot;j++){
    		for(int i=type[j];i<money;i++){
    			if(num[i]>num[i-type[j]]+1){
    				num[i]=num[i-type[j]]+1;
    				path[i]=type[j];
    			}
    		}
    	}
    }
    int main(){
    	int s;
    	sovle();
    	while(cin>>s){
    		cout<<num[s]<<endl;
    		prin(path,s);
    	}
    return 0;
    }
    

    2、每种硬币有数量限制

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    using namespace std;
    const int maxn=1010;
    const int INF=0x3fffffff;
    //所有硬币组合,而且对硬币的数量有限制
    int a[5]={1,5,10,25,50}; 
    int dp[251][110];
    int n;
    //先打表 
    void sovle(){
        dp[0][0]=1;
        for(int i=0;i<5;i++){
            for(int j=1;j<101;j++){
                for(int k=a[i];k<251;k++)
                dp[k][j]+=dp[k-a[i]][j-1];
            }
        }
    }
    int ans[251]={0};
    int main(){
        sovle();
        for(int i=0;i<251;i++){
            for(int j=0;j<101;j++) ans[i]+=dp[i][j]; //从0开始,因为dp[0][0]=1 
        }
        while(cin>>n){
            cout<<ans[n]<<endl;
        
        }
    return 0;
    }
    

    区间贪心

    一、区间不相交问题

    总是选择左端点最大的区间

    struct node{
    	int x,y;
    }a[maxn];
    bool cmp(node a,node b){
    	if(a.x!=b.x) return a.x>b.x;   //先按照左端点从大到小排序 
    	else return a.y<b.y;           //不然就是右端点从小到大 
    }
    sort(a,a+n,cmp);
    int ans=1,lastx=a[0].x;
    for(int i=1;i<n;i++){
    	if(a[i].y<=lastx){
    		ans++;
    		lastx=a[i].x;
    	}
    } 
    

    二、区间选点问题

    最少确定多少个点,才能使每个闭区间都至少存在一个点,和区间不相交问题一样,只需要改成a[i].y<lastx就可以了

    最小生成树算法:常用的是prim和kruskal算法,都是采用了贪心的思想,但是策略不一样。

     三、活动安排问题

    按照结束时间排序

    struct node{
    	int st,ed;
    }ac[maxn];
    bool cmp(node a,node b){
    	return a.ed<b.ed;
    }
    void solve(){
    	int n;cin>>n;
    	for(int i=0;i<n;i++) cin>>ac[i].st>>ac[i].ed;
    	sort(ac,ac+n,cmp);
    	int ans=0;
    	int lastend=-1;
    	for(int i=0;i<n;i++){
    		if(ac[i].st>=lastend){
    			ans++;
    			lastedn=ac[i].ed;
    		}
    	}
    	return ans;
    }
    

    四、区间覆盖问题

    给出线段的左右端点,求最少要多少线段覆盖整个区间

    先按照左端点排序,然后在剩下的里面选择左端点在R且右端点最大的

    五、最优装载问题

    六、多机调度问题

    最长处理时间优先

    背包问题

    一、部分背包问题:可以选择拿一件物品地部分东西,这个完全可以用贪心,选择当前单位价值最大的

    二、01背包问题:因为要和选和不选的两种情况比较,所以产生的子问题互为重叠,需要用动态规划

  • 相关阅读:
    C++ P1890 gcd区间
    C++ P1372 又是毕业季I
    C++ CF822A I'm bored with life
    C++ P4057 [Code+#1]晨跑
    C++ CF119A Epic Game
    关于树状数组的几点总结
    markdown语法
    portal开发"下拉框"“日期框”查询要怎么配置
    泛型总结--待续
    Actioncontext跟ServletActionContext的区别---未完待续
  • 原文地址:https://www.cnblogs.com/shirlybaby/p/12263134.html
Copyright © 2011-2022 走看看