贪心算法-活动安排问题

贪心算法总是作出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。当然,希望贪心算法得到的最终结果也是整体最优的。虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解,如之前的Dijkstra算法,Prim算法,Kruskal算法。如果不要求绝对最佳答案,那么有时候我们使用简单的贪婪算法生成近似的答案.

贪心与动态规划
贪心算法和动态规划都需求最优子结构,但是贪心算法是自顶向下方式进行,就是每一步,根据策略得到一个当前最优解。传递到下一步,从而保证每一步都是选择当前最优的。最后得到结果.每一步的最优解都依赖上一部的最优解.你只考虑之前已做出的选择
而动态规划通常自底向上解各种子问题,每一步,根据策略得到一个更小规模的问题。最后解决最小规模的问题。得到整个问题最优解.全局最优解中一定包含某个局部最优解,但不一定包含前一个局部最优解.你考虑的都是以后的子问题
经典的还是背包问题,之前的01背包问题我们采用动态规划解决而不能用贪心.但是如果改成部分背包问题呢:
假如有三件物品,背包可装50磅的物品,物品1重10磅,价值60元;物品2重20磅,价值100元;物品3重30磅,价值120元。你可以选择带走每个物品的全部或一部分,求如何选择可以使背包所装的价值最大?
注意到不同点是我们可以选择带走一部分,所以使用贪心算法十分自然地想到,先算含金量啊,先把含金量最高的都带完,再带含金量其次的…很容易得到解,带走一件1,一件2,2/3件3…比较简单代码不写.

活动安排问题
设有n个活动的集合E = {1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si < fi 。如果选择了活动i,则它在半开时间区间[si, fi)内占用资源。若区间[si, fi)与区间[sj, fj)不相交,则称活动i与活动j是相容的。也就是说,当si >= fj或sj >= fi时,活动i与活动j相容.怎么尽可能地安排多的相容活动呢?
设待安排的11个活动的开始时间和结束时间按结束时间的非减序排列如下:
这里写图片描述
注意要按结束时间的早晚排列,没排好的话,你可以回去用各种方法自己排.既然贪心么就是越早结束越好,给后面留尽可能多的空间.其次”目光短浅”,从排列好的里一个个选,能选一个是一个,别管后面的…
显然,我们选择到了(1)1-4,(4)5-7,(8)8-11,(11)12-14
感觉不靠谱么,其实对于这个活动安排问题,贪心算法总能求得的整体最优解,即它最终所确定的相容活动集合A的规模最大。这个结论可以用数学归纳法证明。

代码:

public class MArrange1 {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int [] start=initArrange(scanner);
        int [] end=initArrange(scanner);
        int n=start.length;
//        shows(start);
//        shows(end);
        selectSort(start,end,n);
        greedyArrange(start,end,n);
    }

    private static void greedyArrange(int[] start, int[] end, int n) {
        List<Integer> end1=new ArrayList<>();
        List<Integer> start1=new ArrayList<>();
        end1.add(end[0]);
        start1.add(start[0]);
        int startTime=end[0];//选择的所有活动的最末结束时间
        for (int i = 1; i <n ; i++) {
            if(start[i]>startTime)
            {
                end1.add(end[i]);
                start1.add(start[i]);
                startTime=end[i];
            }
        }


        System.out.println("result:");//输出结果
        for(int i:start1)
            System.out.print(i+" ");
        System.out.println();
        for(int i:end1)
            System.out.print(i+" ");
    }

    private static void selectSort(int[] start, int[] end, int n) {
        int [] b=new int[n];
        for (int i = 0; i <n ; i++) {
            b[i]=i;
        }
        for (int i = 0; i <n-1 ; i++) {
            for (int j = i+1; j <n ; j++) {
                if(end[j]<end[i])
                {
                    int temp=end[j];
                    end[j]=end[i];
                    end[i]=temp;

                    int temp1=b[j];
                    b[j]=b[i];
                    b[i]=temp1;
                }
            }
        }
//        shows(end);
//        shows(b);

        int c[]=new int[n];
        for (int i = 0; i <n ; i++) {
            c[i]=start[b[i]];
        }
        start=c;

//        shows(start);

    }

    private static void shows(int[] start) {
        for(int i:start)
            System.out.print(i+" ");
        System.out.println();
    }

    private static int[] initArrange(Scanner scanner) {
        String string=scanner.nextLine();
        String [] strings=string.split(",");
        int [] temp=new  int[strings.length];
        for (int i = 0; i <strings.length ; i++) {
            temp[i]=Integer.parseInt(strings[i]);
        }
        return temp;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值