Skip to content
Snippets Groups Projects
Verified Commit 59d9dbd8 authored by Dmytro Bogatov's avatar Dmytro Bogatov :two_hearts:
Browse files

Redo portals.

Now much cleaner solution and much faster.
parent 67e4c442
Branches
No related tags found
No related merge requests found
......@@ -4,56 +4,89 @@ using System.Linq;
namespace CodingInterview.School
{
/// <summary>
/// cSpell:disable
/// Деякі планети галактики, куди нещодавно переїхав Петрик П’яточкін, сполучено порталами.
/// Якщо планети А і Б сполучено, це означає, що на кожній із планет стоїть спеціальний пристрій — портал — для телепортації між ними.
/// Істота, що входить у портал на планеті А, миттєво опиняється на планеті Б і навпаки.
///
/// Один і той самий портал не можна використовувати для телепортації на різні планети.
/// Якщо між парою планет ще немає сполучення, їх можна сполучити, але лише побудувавши на кожній із них по новому порталу.
/// Будівництво порталів вимагає чималих витрат і може коштувати по-різному на різних планетах.
///
/// Будемо казати, що між двома планетами існує шлях телепортації, якщо з однієї планети можна потрапити на іншу, телепортувавшись один або кілька разів (використовуючи проміжні планети).
/// На жаль, поки що не між кожними двома планетами існує шлях телепортації.
///
/// Маючи схему наявного сполучення планет і знаючи вартість будівництва порталу на кожній планеті, визначте, яку найменшу суму грошей потрібно витратити, щоб забезпечити існування шляху телепортації між кожною парою планет галактики.
/// cSpell:enable
///
/// http://www.kievoi.ippo.kubg.edu.ua/kievoi/3/2013.html
/// </summary>
public class Portals
{
public static int Solve(int[] costs, Tuple<int, int>[] connections)
class Planet
{
var buckets = Enumerable
.Range(1, costs.Count())
.Select(p =>
{
var b = new HashSet<int>();
b.Add(p);
return b;
})
.ToList();
public int Cost { get; set; }
public List<Planet> Neighbors { get; set; } = new List<Planet>();
public bool Visited { get; set; } = false;
}
foreach (var connection in connections)
/// <summary>
/// Returns the minmum amount of money needed to get all plannets connected.
/// </summary>
/// <param name="costs">the costs of building a portal on each planet (index is a planet)</param>
/// <param name="connections">pairs of indices representing planets which already have portals between them</param>
/// <returns>the minmum amount of money needed to get all plannets connected</returns>
public int Solve(int[] costs, (int from, int to)[] connections)
{
HashSet<int> bucket1 = null, bucket2 = null;
foreach (var bucket in buckets)
var planets = new Planet[costs.Length];
for (var planet = 0; planet < costs.Length; planet++)
{
if (bucket.Contains(connection.Item1))
planets[planet] = new Planet { Cost = costs[planet] };
}
foreach (var connection in connections)
{
bucket1 = bucket;
planets[connection.from - 1].Neighbors.Add(planets[connection.to - 1]);
planets[connection.to - 1].Neighbors.Add(planets[connection.from - 1]);
}
if (bucket.Contains(connection.Item2))
var minCosts = new List<int>();
for (var planet = 0; planet < costs.Length; planet++)
{
bucket2 = bucket;
if (planets[planet].Visited)
{
continue;
}
if (bucket1 != null && bucket2 != null)
var minCost = Int32.MaxValue;
var bfsQueue = new Queue<Planet>();
bfsQueue.Enqueue(planets[planet]);
while (bfsQueue.Count > 0)
{
break;
var current = bfsQueue.Dequeue();
if (!current.Visited)
{
minCost = Math.Min(current.Cost, minCost);
current.Visited = true;
foreach (var neighbor in current.Neighbors)
{
if (!neighbor.Visited)
{
bfsQueue.Enqueue(neighbor);
}
}
if (bucket1 != bucket2)
}
}
if (minCost != Int32.MaxValue)
{
bucket1.UnionWith(bucket2);
buckets.Remove(bucket2);
minCosts.Add(minCost);
}
}
var minimalCosts = buckets.Select(b => b.Select(p => costs[p - 1]).Min());
var min = minimalCosts.Min();
var result = min * (minimalCosts.Count() - 1) + (minimalCosts.Sum() - min);
var minOfMin = minCosts.Min();
return result;
return minOfMin * (minCosts.Count - 1) + (minCosts.Sum() - minOfMin);
}
}
}
......@@ -33,7 +33,7 @@ namespace CodingInterview.HackerRank
// get next tile
var (location, path) = queue.Dequeue();
// if it the target tile, we are done
// if it is the target tile, we are done
if (map[location.i, location.j] == 'X')
{
return path;
......
using System;
using System.IO;
using Xunit;
using CodingInterview.School;
using System.Collections.Generic;
using System.Linq;
......@@ -14,11 +13,11 @@ namespace CodingInterview.Tests.School
{
Assert.Equal(
10,
CodingInterview.School.Portals.Solve(
new CodingInterview.School.Portals().Solve(
new int[] { 7, 4, 7, 3 },
new Tuple<int, int>[] {
new Tuple<int, int>(1, 3),
new Tuple<int, int>(2, 4)
new (int from, int to)[] {
(1, 3),
(2, 4)
}
)
);
......@@ -30,15 +29,15 @@ namespace CodingInterview.Tests.School
{
var arguments = ParseFile(fileId.ToString("D2"));
Assert.Equal(arguments.Item3, CodingInterview.School.Portals.Solve(arguments.Item1, arguments.Item2));
Assert.Equal(arguments.answer, new CodingInterview.School.Portals().Solve(arguments.costs, arguments.connections));
}
public static IEnumerable<object[]> Cases(int upTo) => Enumerable.Range(1, upTo).Select(i => new object[] { i });
Tuple<int[], Tuple<int, int>[], int> ParseFile(string name)
(int[] costs, (int from, int to)[] connections, int answer) ParseFile(string name)
{
// Open the text file using a stream reader.
using (StreamReader sr = File.OpenText($"resources/portals/{name}.in"))
using (var sr = File.OpenText($"resources/portals/{name}.in"))
{
// Read the stream to a string, and write the string to the console.
sr.ReadLine();
......@@ -46,20 +45,20 @@ namespace CodingInterview.Tests.School
var costs = sr.ReadLine().Split(' ').Select(s => Int32.Parse(s));
string line;
var connections = new LinkedList<Tuple<int, int>>();
var connections = new LinkedList<(int from, int to)>();
while ((line = sr.ReadLine()) != null)
{
var asArray = line.Split(' ');
connections.AddFirst(new Tuple<int, int>(int.Parse(asArray[0]), int.Parse(asArray[1])));
connections.AddFirst((int.Parse(asArray[0]), int.Parse(asArray[1])));
}
using (StreamReader streamAns = File.OpenText($"resources/portals/{name}.ans"))
using (var streamAns = File.OpenText($"resources/portals/{name}.ans"))
{
// Read the stream to a string, and write the string to the console.
var ans = int.Parse(streamAns.ReadLine());
return new Tuple<int[], Tuple<int, int>[], int>(costs.ToArray(), connections.ToArray(), ans);
return (costs.ToArray(), connections.ToArray(), ans);
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment