public Drone(Input input, int id) { this.input = input; this.id = id; X = input.WareHouses[0].X; Y = input.WareHouses[0].Y; }
public Solution(Input input) { _input = input; _deliveryOrders = new StringBuilder[input.NbDrones]; for (int i = 0; i < input.NbDrones; i++) _deliveryOrders[i] = new StringBuilder(); }
public static Input Parse(string fileName) { var input = new Input(); using(var reader = new StreamReader(fileName)) { var inputParams = reader.ReadLine().Split(' ').Select(Int32.Parse).ToArray(); input.R = inputParams[0]; input.C = inputParams[1]; input.NbDrones = inputParams[2]; input.NbTurns = inputParams[3]; input.MaxPayload = inputParams[4]; reader.ReadLine(); //nb product types, osef input.ProductTypes = reader.ReadLine().Split(' ').Select(Int32.Parse).ToArray(); input.NbWareHouses = Int32.Parse(reader.ReadLine()); input.WareHouses = new WareHouse[input.NbWareHouses]; for(int i = 0; i < input.NbWareHouses; i++) { var coords = reader.ReadLine().Split(' ').Select(Int32.Parse).ToArray(); input.WareHouses[i] = new WareHouse{ X = coords[0], Y = coords[1], id = i, Stock = reader.ReadLine().Split(' ').Select(Int32.Parse).ToArray(), }; } var nbOrders = Int32.Parse(reader.ReadLine()); input.Orders = new Order[nbOrders]; for(int i = 0; i < nbOrders; i++) { var coords = reader.ReadLine().Split(' ').Select(Int32.Parse).ToArray(); var order = new Order { X = coords[0], Y = coords[1], id = i, NbItemsRemaining = Int32.Parse(reader.ReadLine()), ItemsWanted = reader.ReadLine().Split(' ').Select(Int32.Parse).ToArray(), }; order.TotalWeight = order.ItemsWanted.Sum(item => input.ProductTypes[item]); Array.Sort(order.ItemsWanted); input.Orders[i] = order; } } return input; }
public static Input Parse(string fileName) { var input = new Input(); using (var reader = new StreamReader(fileName)) { input.NbTurns = ReadInt(reader); var nbSat = ReadInt(reader); for (int i = 0; i < nbSat; i++) { var line = ReadMulti(reader); var sat = new Satellite( lat: line[0], lon: line[1], speed: line[2], rotSpeed: line[3], maxRot: line[4], id: i); input.Satellites.Add(sat); } var nbCollec = ReadInt(reader); var picId = 0; for (int i = 0; i < nbCollec; i++) { var line = ReadMulti(reader); var collec = new PicCollection(line[0], picId); var nbLoc = line[1]; picId += nbLoc; for (int j = 0; j < nbLoc; j++) { var loc = ReadMulti(reader); collec.Locations.Add(new Coords {Lat = loc[0], Lon = loc[1]}); } var nbRanges = line[2]; for (int j = 0; j < nbRanges; j++) { var time = ReadMulti(reader); collec.TimeRanges.Add(new TimeRange(time[0], time[1])); } input.Collections.Add(collec); } } return input; }
public static Solution Solve(Input input) { var takenPictures = new List<Snapshot>(); var tree = new KdTree<float, PicCollection>(2, new FloatMath()); foreach (var picCollection in input.Collections) { foreach (var pict in picCollection.Locations) { tree.Add(new float[] { pict.Lat, pict.Lon }, picCollection); } } tree.Balance(); var orderedSatellelites = input.Satellites.OrderByDescending(sat => sat.MaxRot).ToList(); for (int s = 0; s < orderedSatellelites.Count; ++s) { var satellite = orderedSatellelites[s]; for (int turn = 0; turn < input.NbTurns; ++turn) { var node = tree.RadialSearch(new float[] { satellite.Pos.Lat, satellite.Pos.Lon }, satellite.MaxRot*SQRT2, 150).ToArray(); if (node.Length > 0) { var valids = node.Where(n => n.Value.PictureCanBeTaken(turn)) .Where(k => satellite.CanTakePicture((int)k.Point[0], (int)k.Point[1])) .OrderByDescending(k => Math.Pow(k.Point[0] - satellite.Pos.Lat, 2) + Math.Pow(k.Point[1] - satellite.Pos.Lon, 2)) //.OrderByDescending(k => k.Value.TakenPictures.Count) .ToList(); if (valids.Count > 0) { Console.WriteLine("Found {0} valid new positions", valids.Count); var pict = valids[0]; var pictCoord = new Coords((int)pict.Point[0], (int)pict.Point[1]); var snap = satellite.TakePicture(pictCoord); takenPictures.Add(snap); pict.Value.TakePicture(pictCoord); pict.Value.Locations.Remove(pictCoord); tree.RemoveAt(pict.Point); Console.WriteLine("Satellite {1} Found {0} pict - Turn {2}", node.Length, satellite.Id, turn); ////Console.WriteLine("Satellite Lat {0} Lon {1} Pict {2} {3} Rot {4} {5}", satellite.Pos.Lat, //satellite.Pos.Lon, pict.Point[0], pict.Point[1], satellite.CurrentRot.Lat, satellite.CurrentRot.Lon); } } satellite.NextTurn(); } } var score = input.Collections.Where(c => c.Locations.Count == 0 && c.TakenPictures.Count > 0).Sum(p => p.Value); var solution = new Solution(takenPictures, score); return solution; }
public static Solution Solve(Input input) { _multidroneMalus = 1.0 + Helper.Rand.NextDouble(); //choose a random malus between 1 and 2 for this run var solution = new Solution(input); var drones = new Drone[input.NbDrones]; for (int d = 0; d < input.NbDrones; d++) { drones[d] = new Drone(input, d); } var iteration = 0; //to ease debuging a particular step while (true) { iteration++; //chooseDrone furthest in the past Drone chosen = drones[0]; for (int d = 1; d < drones.Length; d++) { if (drones[d].turn < chosen.turn) chosen = drones[d]; } if (chosen.turn > input.NbTurns) { Console.WriteLine("end of times reached"); return solution; //can't do shit anymore } //choose order WareHouse wh; var order = GetBestOrder(chosen, input, out wh); if (order == null) { return solution; //no more order to deliver } if (wh != null) { //go to warehouse and load everything for (int i = 0; i < order.ItemsWanted.Length; i++) { var itemType = order.ItemsWanted[i]; if(itemType < 0) continue; wh.Stock[itemType]--; Helper.Assert(() => wh.Stock[itemType] >= 0); chosen.Load(wh, itemType); solution.LoadForDelivery(chosen, wh, order, itemType); } //everything is loaded for (int dd = 0; dd < order.NbItemsRemaining; dd++) { chosen.Deliver(order); } solution.DoDeliver(chosen, order, orderComplete: true); order.ItemsWanted = null; } else //we'll have to go to several warehouses to load stuff OR we'll need several drones { var loadedToDeliver = new List<int>(); var itemsToDeliver = (int[]) order.ItemsWanted.Clone(); while(itemsToDeliver.Any(it => it >= 0)) { //best warehouse with item in stock double bestScore = Double.PositiveInfinity; WareHouse bestwh = null; List<int> availableItems = null; for (int w = 0; w < input.NbWareHouses; w++) { var currentwh = input.WareHouses[w]; var items = currentwh.GetFulfillable(itemsToDeliver); if (items.Count > 0) { var score = (double) Helper.Distance(chosen.X, chosen.Y, currentwh.X, currentwh.Y)/items.Count; //time per item if (score < bestScore) { bestScore = score; bestwh = currentwh; availableItems = items; } } } wh = bestwh; for (int i = 0; i < availableItems.Count; i++) { var itemType = order.ItemsWanted[availableItems[i]]; if (itemType < 0) //already delivered continue; if (!chosen.CheckLoad(wh, itemType)) { //drone passed end of turns or is full goto deliver; //maybe we could stash one or two more small items, but whatever } wh.Stock[itemType]--; itemsToDeliver[availableItems[i]] = -1; chosen.Load(wh, itemType); solution.LoadForDelivery(chosen, wh, order, itemType); loadedToDeliver.Add(availableItems[i]); } } deliver: for (int dd = 0; dd < loadedToDeliver.Count; dd++) { chosen.Deliver(order); } for (int i = 0; i < loadedToDeliver.Count; i++) { Helper.Assert(() => order.ItemsWanted[loadedToDeliver[i]] >= 0); order.TotalWeight -= input.ProductTypes[order.ItemsWanted[loadedToDeliver[i]]]; order.ItemsWanted[loadedToDeliver[i]] = -1; //mark as delivered order.NbItemsRemaining--; } var orderComplete = order.NbItemsRemaining == 0; if (orderComplete) { Helper.Assert(() => order.ItemsWanted.All(it => it < 0)); order.ItemsWanted = null; } else { Helper.Assert(() => order.ItemsWanted.Any(it => it >= 0)); } solution.DoDeliver(chosen, order, orderComplete); } } }
private static Order GetBestOrder(Drone d, Input input, out WareHouse goThere) { goThere = null; int bestCost = Int32.MaxValue; Order best = null; foreach (var order in input.Orders) { if(order.ItemsWanted == null) continue; //already delivered int cost = Int32.MaxValue; WareHouse bestWh = null; var totalWeight = order.TotalWeight; if (totalWeight < input.MaxPayload) //one drone can take care of this order { var eligibleWareHouses = input.WareHouses.Where(wh => wh.CanFullfillOrder(order.ItemsWanted) == order.NbItemsRemaining); if (eligibleWareHouses.Any()) //everything is in the same warehouse { foreach (var wh in eligibleWareHouses) { var dist = Helper.Distance(d.X, d.Y, wh.X, wh.Y) + Helper.Distance(wh.X, wh.Y, order.X, order.Y); if (dist < cost) { cost = dist; bestWh = wh; } } } else //one drone can do everything, but has to go to several warehouses { //simulate going to 3 different wh int dist = 0; var wh = input.WareHouses[Helper.Rand.Next(input.NbWareHouses)]; dist += Helper.Distance(d.X, d.Y, wh.X, wh.Y) * 3; dist += Helper.Distance(order.X, order.Y, wh.X, wh.Y); if (dist < cost) { cost = dist; } } } else //we'll need several drones to complete this order { //simulate going to 3 different wh int dist = 0; var wh = input.WareHouses[Helper.Rand.Next(input.NbWareHouses)]; dist += Helper.Distance(d.X, d.Y, wh.X, wh.Y)*3; dist += Helper.Distance(order.X, order.Y, wh.X, wh.Y); dist = (int)(_multidroneMalus * dist * totalWeight/input.MaxPayload); //apply a malus for estimated nb of drones needed if (dist < cost) { cost = dist; } } if (cost < bestCost) { bestCost = cost; best = order; goThere = bestWh; } } return best; }
public static Solution Solve(Input input) { var tree = BuildTree(input); var satellites = input.Satellites.OrderBy(s => s.MaxRot).ToArray(); var totalNbPic = tree.Count; var solution = new List<Snapshot>(); var picturesConfirmed = new BitArray(totalNbPic); for (int s = 0; s < satellites.Length; s++) { var satellite = satellites[s]; Console.WriteLine($"satellite {s+1}/{satellites.Length} (#{satellite.Id})"); var state = new List<PartialSolution> {new PartialSolution(picturesConfirmed)}; for (int t = 1; t < input.NbTurns; t++) { if (t % 20000 == 0) Console.WriteLine(t); Step(state, satellite); SimplifyRanges(state); //look for pictures to take var candidates = tree.RadialSearch(new float[] {satellite.Pos.Lat, satellite.Pos.Lon}, satellite.MaxRot*SQRT2, 150); //TOO SLOW ! Helper.Assert(() => candidates.Length < 145, candidates.Length); candidates = candidates.Where(node => !picturesConfirmed.Get(node.Value.Item1 + node.Value.Item2.BasePicId) && node.Value.Item2.PictureCanBeTaken(t)).ToArray(); var stopIdx = state.Count; //we're gonna add more, but we don't want to browse'em for (int st = 0; st < stopIdx; st++) { var sol = state[st]; var range = sol.CurrentRange; foreach (var candidate in candidates) { var collec = candidate.Value.Item2; var picIdx = candidate.Value.Item1; if(sol.PicturesTaken.Get(collec.BasePicId + picIdx)) continue; var picLoc = collec.Locations[picIdx]; if (picLoc.IsInRange(range, satellite.Pos)) { var newScore = sol.EstimatedValue + Score(collec, sol); var newRange = new Range(satellite.Pos, picLoc); if (!WorthTaking(newScore, newRange, state)) continue; var newCommands = new List<Snapshot>(sol.Snapshots); newCommands.Add(new Snapshot(picLoc.Lat, picLoc.Lon, t, satellite.Id)); var taken = new BitArray(sol.PicturesTaken); taken.Set(collec.BasePicId + picIdx, true); state.Add(new PartialSolution (newScore, newRange, newCommands, taken)); } } } } PartialSolution best = null; foreach (var partialSolution in state) { if (best == null || partialSolution.EstimatedValue > best.EstimatedValue) best = partialSolution; } solution.AddRange(best.Snapshots); picturesConfirmed.Or(best.PicturesTaken); //union } int score = 0; foreach (var picCollection in input.Collections) { bool complete = true; var stop = picCollection.BasePicId + picCollection.Locations.Count; for (int i = picCollection.BasePicId; i < stop; i++) { if (!picturesConfirmed.Get(i)) { complete = false; break; } } if (complete) score += picCollection.Value; } return new Solution(solution, score); }
private static KdTree<float, Tuple<int, PicCollection>> BuildTree(Input input) { var tree = new KdTree<float, Tuple<int, PicCollection>>(2, new FloatMath()); foreach (var picCollection in input.Collections) { for (int p = 0; p < picCollection.Locations.Count; p++) { var pict = picCollection.Locations[p]; tree.Add(new float[] {pict.Lat, pict.Lon}, Tuple.Create(p, picCollection)); } } tree.Balance(); return tree; }