算法-贪心

对于贪心算法,进行几个简单问题的探讨和学习。

package com.xpn.question;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * 1、删数问题(贪心)deleteK
 * 2、活动安排问题(贪心GreedySelector)arrange
 * 3、会场安排,arrangeMetting
 * @author xpn
 *
 */
public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        //1 test
        /*Integer[] A={1,7,8,5,4,3};
        Object[] res=deleteK(A,4);
        for (Object integer : res) {
            System.out.print(integer);
        }*/
        //2 test
        TimeNode[] times = new TimeNode[11];
        times[0] = new TimeNode(1, 4);
        times[1] = new TimeNode(3, 5);
        times[2] = new TimeNode(0, 6);
        times[3] = new TimeNode(5, 7);
        times[4] = new TimeNode(3, 8);
        times[5] = new TimeNode(5, 9);
        times[6] = new TimeNode(6, 10);
        times[7] = new TimeNode(8, 11);
        times[8] = new TimeNode(8, 12);
        times[9] = new TimeNode(2, 13);
        times[10] = new TimeNode(12, 14);
        arrange(times);


    }
    /*1、删树问题(贪心)deleteK
        问题:给定n位整数q,去掉其中任意k<=n个数字后,剩下的数字按原次序排列组成一个新的正整数。
           对于给定的n位正整数a和正整数k,设计一个算法找出剩下数字组成的新数最小的删数方案。
        比如,178543删除四个数字后,最小的新数是13。*/
    //思路:贪心,每次删除第一个非递增的数字
    private static Object[] deleteK(Integer[] A,int k){
        if(A==null||A.length<=0||k<=0)
            return null;
        List<Integer> list=new ArrayList<Integer>();
        Collections.addAll(list, A);
        int n=A.length;
        if(k<=n){
            while(k>0){
                int i=0;
                for(;i<list.size()-1;i++){
                    if(list.get(i)>list.get(i+1))
                        break;
                }
                list.remove(i);
                k--;
            }
            return  list.toArray();
        }
        return null;
    }
    /*2、活动安排问题(贪心)
    设有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相容。
            由于输入的活动以其完成时间的非减序排列,所以算法greedySelector每次总是选择具有最早完成时间的相容活动加入集合A中。直观上,按这种方法选择相容活动为未安排活动留下尽可能多的时间。也就是说,该算法的贪心选择的意义是使剩余的可安排时间段极大化,以便安排尽可能多的相容活动。
            此算法的效率极高。当输入的活动已按结束时间的非减序排列,算法只需O(n)的时间安排n个活动,使最多的活动能相容地使用公共资源。如果所给出的活动未按非减序排列,可以用O(nlogn)的时间重排。
        */
    private static class TimeNode{
        int s;//开始时间
        int f;//结束时间
        public TimeNode(int s, int f) {
            super();
            this.s = s;
            this.f = f;
        }

    }
    //测试A[]={1,2,3,4,。。。14}
    //TimeNode[] times={}
    private static void arrange(TimeNode[] times){
        Arrays.sort(times, new Comparator<TimeNode>() {

            @Override
            public int compare(TimeNode o1, TimeNode o2) {
                // TODO Auto-generated method stub
                return o1.f-o2.f;//按照结束时间进行排序
            }
        });
        int j=0;//保存上一个安排的活动
        int i,n=times.length;
        int counts=1;//保存安排的活动个数
        System.out.println("安排活动"+j+":("+times[j].s+","+times[j].f+")");
        for(i=1;i<n;i++){
            if(times[i].s>times[j].f){
                j=i;
                counts++;
                System.out.println("安排活动"+j+":("+times[j].s+","+times[j].f+")");
            }
        }
        System.out.println(counts);

    }
    //3、会场安排,arrangeMetting
    /*实际上,可以设计出一个更有效的算法。将n个活动1,2,....,n看做实直线上的n个半闭活动区间[s[i],f[i]],i=1~n。所讨论的问题实际上是求这n个半闭区间的最大重叠数。因为重叠的活动区间所相应的活动是互不相容的。若这n个活动区间的最大重叠数为m,则这m个重叠区间所对应的活动互不相容,因此至少要安排m个会场来容纳这m个活动。

            为了有效地对这n个活动进行安排,首先将n个活动区间的2n个端点排序。然后,用扫描算法,从左到右扫描整个直线。在每个事件点处(即活动的开始时刻或结束时刻)作会场安排。当遇到一个开始时刻s[i],就将活动i安排在一个空闲的会场中。遇到一个结束时刻f[i],就将活动i占用的会场释放到空闲会场栈中,已备使用。
            经过这样一遍扫描后,最多安排了m个会场(m是最大重叠区间数)。因此所作的会场安排是最优的。上述算法所需的计算时间主要用于对2n个区间端点的排序,这需要O(nlogn)计算时间。
    */
    private static class MeetNode{
        int flag;//标识初始时间(1)还是结束时间(0)
        int data;
        public MeetNode(int flag, int data) {
            super();
            this.flag = flag;
            this.data = data;
        }
    }
    private static int arrangeMetting(TimeNode[] times){
        List<MeetNode> meets=new ArrayList<MeetNode>();
        for (TimeNode time : times) {
            meets.add(new MeetNode(1, time.s));
            meets.add(new MeetNode(0, time.f));
        }
        Collections.sort(meets, new Comparator<MeetNode>() {

            @Override
            public int compare(MeetNode o1, MeetNode o2) {
                // TODO Auto-generated method stub
                return o1.data-o2.data;
            }
        });
        int current=0;
        int sum=0;//类似于左括号,右括号的问题,保存最大的重叠数目
        for(int i=0;i<meets.size();i++){
            if(meets.get(i).flag==1){
                current++;
                if(current>sum)
                    sum=current;
            }else {
                current--;
            }
        }
        return sum;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值