1. 程式人生 > 其它 >程式設計師與專案經理

程式設計師與專案經理

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;

/**
 * author:左程雲
 */
public class SDEandPM {

    public static class Program {
        public int index;
        public int pm;
        public int start;
        public int rank;
        public int cost;

        public Program(int index, int pmNum, int begin, int rank, int cost) {
            this.index = index;
            this.pm = pmNum;
            this.start = begin;
            this.rank = rank;
            this.cost = cost;
        }
    }

    public static class PmLoveRule implements Comparator<Program> {

        @Override
        public int compare(Program o1, Program o2) {
            if (o1.rank != o2.rank) {
                return o1.rank - o2.rank;
            } else if (o1.cost != o2.cost) {
                return o1.cost - o2.cost;
            } else {
                return o1.start - o2.start;
            }
        }

    }

    // 大黑盒
    // 每一個pm,有自己的堆(PmLoveRule)
    // 每一個pm的堆裡有堆頂,所有的堆頂會再組成一個,程式設計師堆(程式設計師喜好)
    // void add(...)  專案  pop()
    public static class BigQueues {
        //  PriorityQueue<Program> pmQ = pmQueues.get(i);
        private List<PriorityQueue<Program>> pmQueues;
        // 程式設計師堆(一個,程式設計師共享池)
        private Program[] sdeHeap;
        // indexes[i] -> i號pm的堆頂專案,在sde堆中處在啥位置
        private int[] indexes;
        private int heapsize; // 程式設計師堆的大小

        public BigQueues(int pmNum) {
            heapsize = 0;
            sdeHeap = new Program[pmNum];
            indexes = new int[pmNum + 1];
            for (int i = 0; i <= pmNum; i++) {
                indexes[i] = -1;
            }
            pmQueues = new ArrayList<>();
            // i  pmQueues.get(i)
            for (int i = 0; i <= pmNum; i++) {
                pmQueues.add(new PriorityQueue<Program>(new PmLoveRule()));
            }
        }

        // 當前是否有專案可以彈出被程式設計師做
        public boolean isEmpty() {
            return heapsize == 0;
        }

        /**
         * 加入對應專案經理的專案池,同時更新程式設計師池子
         *
         * @param program
         */
        public void add(Program program) {
            PriorityQueue<Program> pmHeap = pmQueues.get(program.pm);
            pmHeap.add(program);
            // 有可能當前的專案,成了此時pm最喜歡的專案,換堆頂,調整sde堆中的專案
            Program head = pmHeap.peek(); // 現在的堆頂
            // 之前pm在sde堆中的自己的堆頂,sde?
            int heapindex = indexes[head.pm];
            if (heapindex == -1) { // 之前沒堆頂,
                sdeHeap[heapsize] = head;
                indexes[head.pm] = heapsize;
                heapInsert(heapsize++);
            } else { // 加此時的program之前,我有老堆頂
                sdeHeap[heapindex] = head;
                heapInsert(heapindex);
                heapify(heapindex);
            }
        }

        // 程式設計師挑專案,返回挑選的專案
        public Program pop() {
            Program head = sdeHeap[0];
            PriorityQueue<Program> queue = pmQueues.get(head.pm);
            queue.poll();
            if (queue.isEmpty()) { // 此時的pm手上沒有專案了
                swap(0, heapsize - 1);
                sdeHeap[--heapsize] = null;
                indexes[head.pm] = -1;
            } else {
                sdeHeap[0] = queue.peek();
            }
            heapify(0);
            return head;
        }

        private void heapInsert(int index) {
            while (index != 0) {
                int parent = (index - 1) / 2;
                if (sdeLoveRule(sdeHeap[parent], sdeHeap[index]) > 0) {
                    swap(parent, index);
                    index = parent;
                } else {
                    break;
                }
            }
        }

        private void heapify(int index) {
            int left = index * 2 + 1;
            int right = index * 2 + 2;
            int best = index;
            while (left < heapsize) {
                if (sdeLoveRule(sdeHeap[left], sdeHeap[index]) < 0) {
                    best = left;
                }
                if (right < heapsize && sdeLoveRule(sdeHeap[right], sdeHeap[best]) < 0) {
                    best = right;
                }
                if (best == index) {
                    break;
                }
                swap(best, index);
                index = best;
                left = index * 2 + 1;
                right = index * 2 + 2;
            }
        }

        private void swap(int index1, int index2) {
            Program p1 = sdeHeap[index1];
            Program p2 = sdeHeap[index2];
            sdeHeap[index1] = p2;
            sdeHeap[index2] = p1;
            indexes[p1.pm] = index2;
            indexes[p2.pm] = index1;
        }

        private int sdeLoveRule(Program p1, Program p2) {
            if (p1.cost != p2.cost) {
                return p1.cost - p2.cost;
            } else {
                return p1.pm - p2.pm;
            }
        }

    }

    public static class StartRule implements Comparator<Program> {

        @Override
        public int compare(Program o1, Program o2) {
            return o1.start - o2.start;
        }

    }

    public static int[] workFinish(int pms, int sdes, int[][] programs) {
        /**
         * 將所有專案放入佇列
         */
        PriorityQueue<Program> startQueue = new PriorityQueue<Program>(new StartRule());
        for (int i = 0; i < programs.length; i++) {
            Program program = new Program(
                    i, programs[i][0], programs[i][1], programs[i][2], programs[i][3]);
            startQueue.add(program);
        }

        /**
         * 程式設計師在1的時間點都可以工作
         */
        PriorityQueue<Integer> wakeQueue = new PriorityQueue<Integer>();
        for (int i = 0; i < sdes; i++) {
            wakeQueue.add(1);
        }

        BigQueues bigQueues = new BigQueues(pms);
        int finish = 0; /
        int[] ans = new int[programs.length];
        while (finish != ans.length) {
            /**
             * 最早可以工作的程式設計師的時間點,推動時間線
             */
            int sdeWakeTime = wakeQueue.poll();

            /**
             * 如果專案池裡有專案可以啟動,則新增到大佇列
             */
            while (!startQueue.isEmpty()) {
                if (startQueue.peek().start > sdeWakeTime) {
                    break;
                }
                bigQueues.add(startQueue.poll());
            }
            //
            if (bigQueues.isEmpty()) { // 當前時間點並無專案可做
                wakeQueue.add(startQueue.peek().start);
            } else { // 當前時間點有專案可做
                Program program = bigQueues.pop();
                ans[program.index] = sdeWakeTime + program.cost;
                wakeQueue.add(ans[program.index]);
                finish++;
            }
        }
        return ans;
    }

    public static void printArray(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

    public static void main(String[] args) {
        int pms = 2;
        int sde = 2;
        int[][] programs = {{1, 1, 1, 2}, {1, 2, 1, 1}, {1, 3, 2, 2}, {2, 1, 1, 2}, {2, 3, 5, 5}};
        int[] ans = workFinish(pms, sde, programs);
        printArray(ans);
    }

}
心之所向,素履以往 生如逆旅,一葦以航