程式設計師與專案經理
阿新 • • 發佈:2021-10-19
心之所向,素履以往 生如逆旅,一葦以航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); } }