zoukankan      html  css  js  c++  java
  • 贪心(Greedy)学习

    1.介绍

    贪心(Greedy)的算法思想:把整个问题分解成多个步骤,在每个步骤都选取当前步骤的最优方案,直到所有步骤结束;在每一步都不考虑对后序步骤的影响,在后序步骤中也不再回头改变前面的选择。

    简单地说,算法思想即“走一步看一步”目光短浅,因为往往局部的最优组合不一定是全局最优的,

    2.例题

    例1:

    Description

    最少硬币问题:某人带着3种面值的硬币去购物,有1元、2元、5元的,硬币数量不限;他需要支付M元,问怎么支付才能使硬币数量最少?

    思路:根据常识,一般先拿出面值最大的,即5元,再拿出第二大的2元,最后才拿面值最小的1元。这个方案中硬币总数是最少的。

    #include<bits/stdc++.h>
    using namespace std;
    const int NUM = 3;
    const int Value[NUM] = {1,2,5};
    
    int main(){
        int i,money;
        int ans[NUM] = {0};      //记录每种硬币数量
        cin >> money;              //输入钱数
        for(i= NUM-1 ;i>=0 ;i--){   //求每种硬币数量
            ans[i] = money/Value[i];
            money = money - ans[i]*Value[i];
        }
        for(i = NUM-1 ;i>=0 ;i--)
            cout <<Value[i] <<"元硬币数:" << ans[i] <<endl;
        return 0;
    }
        

    这一例题中,用局部最优的方法得到的结果是全局最优,然而局部最优不一定总是全局最优,用贪心法一定能得到最优解吗?

    我们稍微改一下参数,就不一定能得到最优解,甚至无法算出答案

    (1)不能得到最优解情形:例如硬币面值为{ 1,2,4,5,6,}元,支付9元,用贪心算法得到答案是6+2+1(读者可以把程序改一下试试),需要3个硬币,而最优情况为 5+4,即两个硬币

    (2)算不出答案情形:在没有1元硬币时,常常得不到解,如:用{2,3,5}元的硬币,支付9元,用贪心法得到的解是错误的,得不到解,但实际上存在解9 = 5+2+2

    虽然贪心算法不一定能得到最优解,但是思路简单、编程容易,因此当确定问题可以通过贪心法得到最优解,那么就使用它。

    例2:

    Description
    某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹.
    怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统.
    Sample Input
    
    8 389 207 155 300 299 170 158 65
    
    
     
    
    
    Sample Output
    
    2
    
    #include<stdio.h>
    int a[30001];//存储每个列表中最后一项(也是最小的一项)
    int main()
    {
        int n,i,j;
        while (~scanf("%d",&n))
        {
            int k=0;
            for (i = 0; i<n; i++)
            {
                scanf("%d",&a[k]);//作为哨兵
                j=0;
                while(a[k]>a[j])
                    j++;
                a[j]=a[k];//将新值放入这个合适的列表(任意合适的列表都可以,这里取第一个合适的)
                k=(k==j)?k+1:k;//如果扫描到哨兵,说明前面的列表没有一个可以存放当前值,创建新列表
                printf("%d %d %d
    ",j,k,a[j]);
            }
            printf("%d
    ",k);//输出最后的列表数
        }
        return 0;
    }

    例3:

    Description:

    乘船问题(入门)

    题目:有n个人,第i个人的重量为wi,每艘船的最大载重量均为C,且最多只能乘两个人。用最少的船装载所有人。

    分析:

    贪心法!

               考虑最轻的人i,他应该和谁一起坐呢?如果每个人都无法和他一起坐船,那么唯一的方案就是每个人坐一艘船!

               否则,他应该选择能和他一起坐船的人中最重的一个j

               这样的方法是贪心的!因为:它只是让“眼前”的浪费最少。

    程序实现:我们只需用两个下标ij分别表示当前考虑的最轻的人和最重的人,每次先将j往左移动,直到ij可以共坐一艘船,然后i1j1。并且重复上述操作!

    复杂度是o(n)

    #include <iostream>
    #include <string>
    #include <algorithm>
    using namespace std;
     
    const int MAXN = 10000;
    int arr[MAXN];
     
    int main() {
        int n, C;   //C表示每艘船的最大载重量
        cin >> n >> C;
        for(int i = 1; i <= n; ++i) {
            cin >> arr[i];
        }
        sort(arr+1, arr+n+1);
        int i = 1, j = n;
        int ans = 0;
        while(i < j) {
            if(arr[i] + arr[j] > C) j--;
            else if(arr[i] + arr[j] <= C) { //两个人可以同乘一艘船
                ans++;
                i++;
                j--;
            }
        }
        cout << ans + n - (2*ans) << endl; 
        return 0;
    }

     例4:勇者斗恶龙

    Description:

    你的王国里有一条n个头的恶龙,你希望雇一些骑士把它杀死(即砍掉所有头)。村里有m个骑士可以雇佣,一个能力值为x的骑士可以砍掉恶龙一个直径不超过x的头,且需要支付x个金币。如何雇佣骑士才能砍掉恶龙的所有头,且需要支付的金币最少?注意,一个骑士只能砍一个头(且不能被雇佣两次)。

    输入格式

    输入包含多组数据。每组数据的第一行为正整数nm1n,m20 000);以下n行每行为一个整数,即恶龙每个头的直径;以下m行每行为一个整数,即每个骑士的能力。输入结束标志为n=m=0

    输出格式

    对于每组数据,输出最少花费。如果无解,输出Loowater

    is doomed!”。

    样例输入
    2 3
    5
    4
    7
    8
    4
    2 1
    5
    5
    10
    0 0
    
    样例输出
    11
    Loowater is doomed!
    
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define maxn 200005
    
    using namespace std;
    
    
    int main()
    {
        int m,n;
        while(scanf("%d%d",&m,&n)==2&&m!=0&&n!=0)
        {
            int i,j,flag=1;
            int  a[maxn],b[maxn];
            for(i=0; i<m; i++)
                scanf("%d",&a[i]); //龙头
            sort(a,a+m);
            for(j=0; j<n; j++)
                scanf("%d",&b[j]); //骑士
            sort(b,b+n); 
            int  h=0;
            if(m>n) //龙头数多于骑士数
                flag=0;
            else
            {
                i=0,j=0;
                int x=0,y=0;
                while(a[0]>b[j])
                {
                    j++; 
                }
                i=0;
                int z=1;
                while(m--)
                {
                    if(a[i]<=b[j])
                    {
                      h+=b[j++];y++;
                    }
                    else
                    {
                        while(a[i]>b[j])
                        {
                            j++;
                            if(j>n)
                            {
                               z=0;
                               flag=0;
                               break;
                            }
                        }
                        h+=b[j++];  y++;
                    }
            
                    if(!z)
                        break;
                }
            }
            if(!flag)
                printf("Loowater is doomed!
    ");
            else
                printf("%d
    ",h);
        }
    }
  • 相关阅读:
    Struts2的struts.properties文件在哪儿啊?
    StrutsPrepareAndExecuteFilter的作用
    【转】Eclipse配置Struts2问题:ClassNotFoundException: org...dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    怎么找到MyEclipse->add struts capabilities
    图像金字塔
    浅析人脸检测之Haar分类器方法
    SIFT算法学习
    OpenCV3.1使用SIFT
    OpenCV头文件包含问题
    OpenCV例程实现人脸检测
  • 原文地址:https://www.cnblogs.com/wxx23-IOU/p/13635198.html
Copyright © 2011-2022 走看看