مساله:
یک ساختمان چند طبقه دارای آسانسور است.
مردم در طبقات مختلف در صف انتظار برای آسانسور هستند.
بعضی ها می خواهند بالا بروند. بعضی ها می خواهند پایین بیایند.
طبقه ای که می خواهند به آنجا بروند با یک عدد نشان داده می شود (یعنی وقتی وارد آسانسور می شوید و آن دکمه ای است که باید فشار دهید)
قوانین
قوانین آسانسور
- آسانسور فقط بالا یا پایین می رود!
- هر طبقه دارای دکمه های بالا و پایین برای صدا زدن آسانسور است (به استثنای طبقه بالا و پایین که به ترتیب فقط DOWN و UP دارند)
- آسانسور هرگز جهت خود را تغییر نمی دهد تا زمانی که دیگر افراد مایل به سوار شدن یا پیاده شدن در مسیری که در حال حرکت است وجود نداشته باشد
- وقتی خالی است ، آسانسور سعی می کند هوشمند باشد. مثلا،
- اگر بالا می رفت شاید برای اینکه افرادی که می خواهند به پایین بیان و طبقه های بالاتر هستند، به بالا رفتن ادامه دهد.
- اگر پایین می رفت شاید برای اینکه افرادی که می خواهند از طبقه های پایین به بالا بروند، به پایین رفتن ادامه دهد.
- آسانسور یک حداکثر ظرفیت برای تعداد اشخاص دارد
- زمانی که آسانسور صدا زده می شود، آسانسور حتی اگر پر باشد در طبقه متوقف می شود، ولی تا زمانی که کسی پیاده نشود کسی هم نمی تواند سوار شود.
- اگر آسانسور خالی است و هیچ کس منتظر نیست، به طبقه همکف باز می گردد
قوانین اشخاص
- اشخاصی که در صف هستند ترتیبشان بر اساس ورودشان به آسانسور است
- همه افراد می توانند دکمه های بالا/پایین Lift-call را فشار دهند
- فقط افرادی که از جهت مساوی با آسانسور حرکت می کنند ممکن است وارد آن شوند
- ورود طبق دستور “صف” است ، اما کسانی که نمی توانند وارد شوند، کسانی را که پشت سر آنها هستند را مسدود نمی کنند
- اگر یک نفر نتواند وارد آسانسور شود، باید بعد از اینکه آسانسور بدون آن ها حرکت کرد، دوباره دکمه صدا زدن بالا/پایین آسانسور را فشار دهد
وظیفه کاتا
- در حالی که از قوانین آسانسور و قوانین اشخاص پیروی می کنید، همه افراد را به طبقه ای که می خواهند بروند برسانید
- لیستی از تمام طبقه هایی که آسانسور در آنها متوقف شده است را برگردانید (به ترتیب بازدید!)
توجه: آسانسور همیشه از طبقه همکف شروع می شود (و افرادی که در طبقه همکف منتظر هستند ممکن است بلافاصله وارد شوند)
ورودی
- queue لیستی از تمام افراد برای تمام طبقات ساختمان است
- ارتفاع ساختمان متفاوت است
- 0 = طبقه همکف
- همه طبقات صف ندارند
- شاخص صف [0] “سر” صف است
- Numbers نشان می دهد که فرد می خواهد به کدام طبقه برود
- capacity حداکثر تعداد افراد مجاز در آسانسور است
تمام پارامترهای ورودی درست هستند.
خروجی
لیستی از تمام طبقه هایی که آسانسور در آنها ایستاده است (به ترتیب بازدید!)
Synopsis
A multi-floor building has a Lift in it.
People are queued on different floors waiting for the Lift.
Some people want to go up. Some people want to go down.
The floor they want to go to is represented by a number (i.e. when they enter the Lift this is the button they will press)
Rules
Lift Rules
The Lift only goes up or down!
Each floor has both UP and DOWN Lift-call buttons (except top and ground floors which have only DOWN and UP respectively)
The Lift never changes direction until there are no more people wanting to get on/off in the direction it is already travelling
When empty the Lift tries to be smart. For example,
If it was going up then it may continue up to collect the highest floor person wanting to go down
If it was going down then it may continue down to collect the lowest floor person wanting to go up
The Lift has a maximum capacity of people
When called, the Lift will stop at a floor even if it is full, although unless somebody gets off nobody else can get on!
If the lift is empty, and no people are waiting, then it will return to the ground floor
People Rules
People are in “queues” that represent their order of arrival to wait for the Lift
All people can press the UP/DOWN Lift-call buttons
Only people going the same direction as the Lift may enter it
Entry is according to the “queue” order, but those unable to enter do not block those behind them that can
If a person is unable to enter a full Lift, they will press the UP/DOWN Lift-call button again after it has departed without them
Kata Task
Get all the people to the floors they want to go to while obeying the Lift rules and the People rules
Return a list of all floors that the Lift stopped at (in the order visited!)
NOTE: The Lift always starts on the ground floor (and people waiting on the ground floor may enter immediately)
I/O
Input
queues
a list of queues of people for all floors of the building.
The height of the building varies
0 = the ground floor
Not all floors have queues
Queue index [0] is the “head” of the queue
Numbers indicate which floor the person wants go to
capacity
maximum number of people allowed in the lift
Parameter validation – All input parameters can be assumed OK. No need to check for things like:
People wanting to go to floors that do not exist
People wanting to take the Lift to the floor they are already on
Buildings with < 2 floors
Basements
Output
A list of all floors that the Lift stopped at (in the order visited!)
Example
Refer to the example test cases.
راه حل ها:
import java.util.ArrayList; import java.util.Arrays; public class Dinglemouse { public static int[] theLift(final int[][] queues, final int capacity) { //Initialize lift ArrayList<Integer> stop = new ArrayList<>(); boolean direction = true; //True up, False down int floor = 0; stop.add(floor); ArrayList<Integer> lift = new ArrayList<>(); while (!isEmpty(queues) || !lift.isEmpty()) { //If at end turn around if (direction && floor == queues.length - 1) direction = false; else if (!direction && floor == 0) direction = true; //Remove people that want to be at this floor if (lift.contains(floor)) { stop.add(floor); lift.removeAll(new ArrayList<>(Arrays.asList(floor))); } //Add people that want to go in direction (if there's space) //Still stops if there are people that want to go in direction ArrayList<Integer> newFloor = new ArrayList<>(); for (int i = 0; i < queues[floor].length; i++) { int target = queues[floor][i]; if (stop.get(stop.size() - 1) != floor && (target > floor) == direction) stop.add(floor); if (lift.size() < capacity && (target > floor) == direction) lift.add(target); else newFloor.add(target); } queues[floor] = newFloor.stream().mapToInt(i -> i).toArray(); //Go to next floor floor = (direction) ? floor + 1 : floor - 1; } //End at ground floor floor = 0; if (stop.get(stop.size() - 1) != floor) stop.add(floor); //Create array from list return stop.stream().mapToInt(i -> i).toArray(); } private static boolean isEmpty(int[][] queues) { for (int[] queue : queues) if (queue.length != 0) return false; return true; } }
import java.util.*; import java.util.stream.Collectors; public class Dinglemouse { private static List<Integer> moves; private static int stage, moving, capa; // moving : 1 = up ; -1 = down private static List<List<Integer>> peopleOnFloorsLists; private static List<Integer> inLift; private static boolean PRINTING = false; private static boolean PRINTING_PARAMS = true; private static List<List<Integer>> cstrStacks(final int[][] queues) { List<List<Integer>> stks = new ArrayList<List<Integer>>(); for (int n = 0 ; n < queues.length ; n++) { stks.add( Arrays.stream(queues[n]) .boxed() .collect(Collectors.toList()) ); } return stks; } public static int[] theLift(final int[][] queues, final int capacity) { if (PRINTING_PARAMS) { System.out.println( Arrays.deepToString(queues) ); System.out.println(capacity); } stage = -1; moving = 1; capa = capacity; peopleOnFloorsLists = cstrStacks(queues); inLift = new ArrayList<Integer>(); moves = new ArrayList<Integer>(); moves.add(0); while (isStillPeopleToBeLifted() || !liftIsEmpty() ) { stage += moving; if (somePeopleIn_WantToGoOut() || someGuysWaitingSameWay_AtThatFloor(stage) ) { liftStopAtThisStage(); somePeopleIn_GoOut(); takeIn_AllPeopleGoingTheSameWay(); } if (PRINTING) { System.out.println(peopleOnFloorsLists); System.out.println("" + stage + " | Inside: " + inLift + " ; " + moves); } /* Decide what the lift has to do now, considering that people inside have the priority: * * No change of direction in these cases : * - If the lift contains people going in the same direction: They have the priority... * - If there are people further that want to go in the same direction... * - If the lift is Empty and that some people further want to go in the other direction, * the lift goes as far as it can before taking in some people again (who wana go to * in the other direction). * * In other cases, the lift begins to move the other way. * For the simplicity of the implementation, the lift is shifted one step backward, so it * will be able to managed the presence of people at the current floor (before update) who * want to go in the other direction. */ if ( !(anyPeopleIn_GoingSameWay() || areSomeGuysFurther_WaitingForSameWay() || (liftIsEmpty() && areSomeGuysFurther_WantingForTheOtherWay()) )) { moving *= -1; stage -= moving; } } liftStopAtThatStage(0); // return to the ground if needed if (PRINTING) System.out.println("" + stage + " | Inside: " + inLift + " ; " + moves); return moves.stream().mapToInt( i -> i.intValue() ).toArray(); } private static boolean isStillPeopleToBeLifted() { return !peopleOnFloorsLists.stream().allMatch( l -> l.isEmpty() ); } private static boolean liftIsEmpty() { return inLift.isEmpty(); } private static boolean somePeopleIn_WantToGoOut() { return inLift.contains(stage); } private static void somePeopleIn_GoOut() { inLift = inLift.stream().filter( i -> i != stage ).collect(Collectors.toList()); } private static void liftStopAtThisStage() { liftStopAtThatStage(stage); } private static void liftStopAtThatStage(int lvl) { if (moves.get(moves.size()-1) != lvl) moves.add(lvl); } private static boolean anyPeopleIn_GoingSameWay() { return inLift.stream().anyMatch( guy -> guy * moving > stage * moving ); } private static boolean areSomePeopleAtThisFloor(int lvl) { return !peopleOnFloorsLists.get(lvl).isEmpty(); } private static boolean someGuysWaitingSameWay_AtThatFloor(int lvl) { return areSomePeopleAtThisFloor(lvl) && peopleOnFloorsLists.get(lvl).stream().anyMatch( i -> i * moving > lvl * moving ); } private static void takeIn_AllPeopleGoingTheSameWay() { List<Integer> peopleGoingIn = new ArrayList<Integer>(), peopleThere = peopleOnFloorsLists.get(stage); // Get all people who can enter the lift, according to its // capacity and the queue order: for (int n = 0 ; n < peopleThere.size() ; n++ ) { if (peopleGoingIn.size() + inLift.size() == capa) break; if (peopleThere.get(n) * moving > stage * moving) peopleGoingIn.add( peopleThere.get(n) ); } inLift.addAll(peopleGoingIn); // update the lift content // Remove the new people in the lift from this floor: while (!peopleGoingIn.isEmpty()) peopleOnFloorsLists.get(stage).remove(peopleGoingIn.remove(0)); } private static boolean areSomeGuysFurther_WaitingForSameWay() { for (int i = stage+moving ; 0 <= i && i < peopleOnFloorsLists.size() ; i += moving) if (someGuysWaitingSameWay_AtThatFloor(i)) return true; return false; } private static boolean areSomeGuysFurther_WantingForTheOtherWay() { for (int i = stage+moving ; 0 <= i && i < peopleOnFloorsLists.size() ; i += moving) if (areSomePeopleAtThisFloor(i)) return true; return false; } }
import java.util.*; public class Dinglemouse { public static int[] theLift(final int[][] queues, final int capacity) { int[][] people = queues; List<Integer> s = new ArrayList<>(); List<Integer> ss = new ArrayList<>(); boolean go = true; int h = 0; int top = 0; do { boolean flag = false; if (go) { for (int i = h; i < people.length; i++) { boolean next = true; if (!ss.isEmpty() && ss.contains(i)) { ss.removeAll(Arrays.asList(i)); s.add(i); next = false; top = i; } if (people[i].length > 0) { h = i; int last = people[i].length; int sy = people[i].length; boolean isUp = false; for (int j = 0; j < people[i].length; j++) { if (people[i][j] == -1) { sy--; } else if (people[i][j] > i) { if (capacity > ss.size()) { ss.add(people[i][j]); last--; people[i][j] = -1; sy--; } else { isUp = true; } } } if (last < people[i].length && next && !(h == top && h == i) || (isUp && last == people[i].length)) { s.add(i); } if (sy > 0) { flag = true; } else { people[i] = new int[0]; } } } go = false; } else { int d = h; for (int i = h; i >= 0; i--) { boolean next = true; if (!ss.isEmpty() && ss.contains(i)) { ss.removeAll(Arrays.asList(i)); s.add(i); next = false; top = i; } if (people[i].length > 0) { d = i; int last = people[i].length; int sy = people[i].length; boolean isDown = false; for (int j = 0; j < people[i].length; j++) { if (people[i][j] == -1) { sy--; } else if (people[i][j] < i) { if (capacity > ss.size()) { ss.add(people[i][j]); people[i][j] = -1; sy--; last--; } else { isDown = true; } } } if (last < people[i].length && next && !(h == top && h == i) || (isDown && last == people[i].length)) { s.add(i); } if (sy > 0) { flag = true; } else { people[i] = new int[0]; } } } h = d; go = true; } if (!flag && ss.isEmpty()) break; } while (true); if (s.isEmpty()) { return new int[] { 0 }; } if (s.get(0) != 0) { s.add(0, 0); } if (s.get(s.size() - 1) != 0) { s.add(0); } int[] r = new int[s.size()]; for (int i = 0; i < s.size(); i++) { r[i] = s.get(i); } return r; } }
import java.util.*; public class Dinglemouse { public static int[] theLift(final int[][] queues, final int capacity) { // Your code here Boolean goingUp = true; int currentFloor = 0; Boolean complete = false; ArrayList<Integer> floorArr = new ArrayList<Integer>(); ArrayList<Integer> currentOccupants = new ArrayList<Integer>(); int occupants = 0; while(!complete) { if(goingUp) { int allaboard = 0; while(currentOccupants.contains(currentFloor)) { occupants--; currentOccupants.remove(currentOccupants.indexOf(currentFloor)); allaboard++; } if(queues[currentFloor].length > 0) { for(int entry = 0; entry < queues[currentFloor].length; entry++) { int destination = queues[currentFloor][entry]; if(destination > currentFloor && destination != 99 && occupants < capacity) { occupants++; currentOccupants.add(destination); queues[currentFloor][entry] = 99; allaboard++; } else if(destination > currentFloor && destination != 99 && occupants == capacity) { allaboard++; } } } if(allaboard > 0 || floorArr.isEmpty()) floorArr.add(currentFloor); if(currentFloor == queues.length-2) goingUp=false; currentFloor++; } else { int allaboard = 0; while(currentOccupants.contains(currentFloor)) { occupants--; currentOccupants.remove(currentOccupants.indexOf(currentFloor)); allaboard++; } if(queues[currentFloor].length > 0) { for(int entry = 0; entry < queues[currentFloor].length; entry++) { int destination = queues[currentFloor][entry]; if(destination < currentFloor && destination != 99 && occupants < capacity) { occupants++; currentOccupants.add(destination); queues[currentFloor][entry] = 99; allaboard++; } else if(destination < currentFloor && destination != 99 && occupants == capacity) { allaboard++; } } } if(allaboard > 0) floorArr.add(currentFloor); if(currentFloor == 1) goingUp=true; currentFloor--; } int num = 0; for(int floor = 0; floor < queues.length; floor++) { for(int queue = 0; queue < queues[floor].length; queue++) { if(queues[floor][queue] != 99) num+=2; } } if(num == 0 && currentOccupants.isEmpty()) complete = true; } if(floorArr.get(floorArr.size()-1) != 0) floorArr.add(0); for(int x2 = 1; x2 < floorArr.size(); x2++) { if(floorArr.get(x2) == floorArr.get(x2-1)) floorArr.remove(x2); } int[] floorArr2 = new int[floorArr.size()]; int c = 0; for(int x7 : floorArr) { floorArr2 = x7; c++; } return floorArr2; } }
import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; public class Dinglemouse { private static List<Integer> stops; private static Map<Integer, List<Integer>> queues; private static Integer currentFloor; private static boolean movingUp; private static int capacity; private static List<Integer> peopleInLift; public static int[] theLift(final int[][] _queues, final int _capacity) { initialize(_queues, _capacity); while (!isJobDone()) { maybeOpenLiftDoor(); move(); } moveToGroundFloor(); return stops.stream().mapToInt(a -> a).toArray(); } private static void initialize(final int[][] _queues, final int _capacity) { capacity = _capacity; stops = new ArrayList<>() {{ add(0); }}; queues = new HashMap<>(); peopleInLift = new ArrayList<>(); currentFloor = 0; movingUp = true; for (int i = 0; i < _queues.length; i++) { queues.put(i, new ArrayList<>()); for (int j = 0; j < _queues[i].length; j++) { queues.get(i).add(j, _queues[i][j]); } } } private static void maybeOpenLiftDoor() { boolean exited = exitLift(); boolean entered = enterLift(); if (exited || entered || isWaitingForLiftOnCurrentFloor()) addStop(); } private static boolean exitLift() { return peopleInLift.removeAll(List.of(currentFloor)); } private static boolean isWaitingForLiftOnCurrentFloor() { return queues.get(currentFloor).stream().anyMatch(people -> (movingUp && people > currentFloor) || (!movingUp && people < currentFloor)); } private static boolean enterLift() { boolean entered = false; List<Integer> itemsToRemove = new ArrayList<>(); for (int i = 0; i < queues.get(currentFloor).size(); i++) { if (capacity == peopleInLift.size()) break; if ((movingUp && queues.get(currentFloor).get(i) > currentFloor) || (!movingUp && queues.get(currentFloor).get(i) < currentFloor)) { peopleInLift.add(queues.get(currentFloor).get(i)); itemsToRemove.add(i); entered = true; } } Collections.reverse(itemsToRemove); itemsToRemove.forEach(item -> queues.get(currentFloor).remove((int) item)); return entered; } private static void move() { if (movingUp) { boolean waitingInUpperFloors = queues.entrySet().stream() .filter(entry -> entry.getKey() > currentFloor) .map(Map.Entry::getValue) .anyMatch(waitingPeople -> !waitingPeople.isEmpty()); if (peopleInLift.size() > 0 || waitingInUpperFloors) { currentFloor++; } else { movingUp = false; } } else if (currentFloor != 0) { currentFloor--; } else { movingUp = true; } } private static boolean isJobDone() { return peopleInLift.isEmpty() && nobodyInQueue(); } private static boolean nobodyInQueue() { return queues.values().stream().allMatch(List::isEmpty); } private static void addStop() { if (!stops.get(stops.size() - 1).equals(currentFloor)) stops.add(currentFloor); } private static void moveToGroundFloor() { currentFloor = 0; addStop(); } }
import java.util.*; public class Dinglemouse { private static class HalfQueue { final int floor; final Queue<Integer> passengers; HalfQueue(int floor, Queue<Integer> passengers) { this.floor = floor; this.passengers = passengers; } } private static class QueueManager { final LinkedList<HalfQueue> upQueues = new LinkedList<>(); final LinkedList<HalfQueue> downQueues = new LinkedList<>(); boolean goingUp; Iterator<HalfQueue> iter; void addQueue(int floor, Queue<Integer> queue, boolean up) { if (!queue.isEmpty()) (up ? upQueues : downQueues).add(new HalfQueue(floor, queue)); } HalfQueue getNext(boolean changeDirection) { if (changeDirection) { goingUp = !goingUp; iter = goingUp ? upQueues.iterator() : downQueues.descendingIterator(); } return iter.hasNext() ? iter.next() : null; } void removeCurrent() { iter.remove(); } } public static int[] theLift(final int[][] queues, final int capacity) { QueueManager queueManager = new QueueManager(); int maxFloor = queues.length - 1; for (int floor = 0; floor <= maxFloor; floor++) { Queue<Integer> upQueue = new ArrayDeque<>(); Queue<Integer> downQueue = new ArrayDeque<>(); for (int dest : queues[floor]) if (dest > floor) upQueue.add(dest); else downQueue.add(dest); queueManager.addQueue(floor, upQueue, true); queueManager.addQueue(floor, downQueue, false); } Queue<Integer> lift = new PriorityQueue<>(capacity); int floor = 0; int direction = 1; // 1 when the Lift moves up, -1 when the Lift moves down HalfQueue nextWaiting = queueManager.getNext(true); List<Integer> stops = new ArrayList<>(); while (true) { stops.add(floor); // disembark while (true) { Integer passenger = lift.peek(); if (passenger == null || passenger * direction != floor) break; lift.poll(); } // embark if (nextWaiting != null && nextWaiting.floor == floor) { Queue<Integer> passengers = nextWaiting.passengers; while (lift.size() < capacity) { lift.add(passengers.poll() * direction); if (passengers.isEmpty()) { queueManager.removeCurrent(); break; } } nextWaiting = queueManager.getNext(false); } // determine the next floor to stop Integer nextGetOff = lift.peek(); if (nextGetOff != null || nextWaiting != null) { if (direction > 0) floor = Math.min(nextGetOff == null ? maxFloor : nextGetOff, nextWaiting == null ? maxFloor : nextWaiting.floor); else floor = Math.max(nextGetOff == null ? 0 : -nextGetOff, nextWaiting == null ? 0 : nextWaiting.floor); } else { direction = -direction; nextWaiting = queueManager.getNext(true); if (nextWaiting == null) { direction = -direction; nextWaiting = queueManager.getNext(true); if (nextWaiting == null) { if (floor != 0) stops.add(0); break; } } int nextFloor = nextWaiting.floor; if (nextFloor == floor) stops.remove(stops.size() - 1); // remove a duplicate else floor = nextFloor; } } return stops.stream().mapToInt(Integer::intValue).toArray(); } }