найденный этой загадкой ЗДЕСЬ... Я сделал решение для грубой силы, и я хотел бы знать, как Вы woul решаете его...
Шум, Woody, Король, и Хамм должны сбежать из Zurg (a), Они просто должны пересечь один последний мост, прежде чем они будут свободны. Однако мост хрупок и может содержать самое большее двух из них одновременно. Кроме того, для пересечения моста фонарь необходим для предотвращения прерываний и сломанных деталей. Проблема состоит в том, что у наших друзей есть только один фонарь с одной батареей, которая служит в течение только 60 минут (это не опечатка: шестьдесят). Игрушки нуждаются в различных временах для пересечения моста (в любом направлении):
TOY TIME
Buzz 5 minutes
Woody 10 minutes
Rex 20 minutes
Hamm 25 minutes
С тех пор может быть только две игрушки на мосту одновременно, они не могут пересечь мост внезапно. Так как им нужен фонарь для пересечения моста, каждый раз, когда два пересекли мост, кто-то должен возвратиться и принести фонарь к тем игрушкам с другой стороны, которые все еще должны пересечь мост. Проблема теперь: В котором порядке эти четыре игрушки могут пересечь мост вовремя (то есть, через 60 минут), чтобы быть сохраненными от Zurg?
//(a) These are characters from the animation movie “Toy Story 2”.
вот мое решение:
public Form1()
{
InitializeComponent();
List toys = new List(){
new toy { name = "buzz", time = 5 } ,
new toy { name = "woody", time = 10 } ,
new toy { name = "rex", time = 20 } ,
new toy { name = "ham", time = 25 } ,
};
var posibles = Combinaciones(toys, 4).ToList(); //all permutations
List> solutions = new List>();
foreach (var pointA in posibles)
{
string order = "";
int flashlight = 60;
List pointB = new List();
do
{
var fastestInA = pointA.Take(2).ToList();
flashlight -= fastestInA.Max(t => t.time);
order += "go " + String.Join(",", fastestInA.Select(t => t.name)) + "\n";
fastestInA.ForEach(t => pointA.Remove(t));
pointB.AddRange(fastestInA);
if (pointB.Count < 4)
{
var fastestInB = pointB.Take(1).ToList();
flashlight -= fastestInB.Max(t => t.time);
order += "return " + String.Join(",", fastestInB.Select(t => t.name).ToArray()) + "\n";
fastestInB.ForEach(t => pointB.Remove(t));
pointA.AddRange(fastestInB);
}
} while (pointB.Count != 4);
solutions.Add(new Tuple(order, flashlight));
}
var optimal = solutions.Where(s => s.Item2 == solutions.Max(t => t.Item2)).ToList();
optimal.ForEach(s => Console.Write("Order:\n" + s.Item1 + "TimeLeft:" + s.Item2 + "\n\n"));
}
public class toy
{
public int time { get; set; }
public string name { get; set; }
}
// this is to do permutations
public static List> Combinaciones(List list, int take)
{
List> combs = new List>();
foreach (var item in list)
{
var newlist = list.Where(i => !i.Equals(item)).ToList();
var returnlist = take <= 1 ? new List> { new List() } : Combinaciones(newlist, take - 1);
foreach (var l in returnlist)
{
l.Add(item);
}
combs.AddRange(returnlist);
}
return combs.ToList();
}
}
Рекурсивное решение с использованием LINQ:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Zurg
{
class Program
{
static readonly Toy[] toys = new Toy[]{
new Toy("Buzz", 5),
new Toy("Woody", 10),
new Toy("Rex", 20),
new Toy("Ham", 25),
};
static readonly int totalTorch = 60;
static void Main()
{
Console.WriteLine(Go(new State(toys, new Toy[0], totalTorch, "")).Message);
}
static State Go(State original)
{
var final = (from first in original.Start
from second in original.Start
where first != second
let pair = new Toy[]
{
first,
second
}
let flashlight = original.Flashlight - pair.Max(t => t.Time)
select Return(new State(
original.Start.Except(pair),
original.Finish.Concat(pair),
flashlight,
original.Message + string.Format(
"Go {0}. {1} min remaining.\n",
string.Join(", ", pair.Select(t => t.Name)),
flashlight)))
).Aggregate((oldmax, cur) => cur.Flashlight > oldmax.Flashlight ? cur : oldmax);
return final;
}
static State Return(State original)
{
if (!original.Start.Any())
return original;
var final = (from toy in original.Finish
let flashlight = original.Flashlight - toy.Time
let toyColl = new Toy[] { toy }
select Go(new State(
original.Start.Concat(toyColl),
original.Finish.Except(toyColl),
flashlight,
original.Message + string.Format(
"Return {0}. {1} min remaining.\n",
toy.Name,
flashlight)))
).Aggregate((oldmax, cur) => cur.Flashlight > oldmax.Flashlight ? cur : oldmax);
return final;
}
}
public class Toy
{
public string Name { get; set; }
public int Time { get; set; }
public Toy(string name, int time)
{
Name = name;
Time = time;
}
}
public class State
{
public Toy[] Start { get; private set; }
public Toy[] Finish { get; private set; }
public int Flashlight { get; private set; }
public string Message { get; private set; }
public State(IEnumerable<Toy> start, IEnumerable<Toy> finish, int flashlight, string message)
{
Start = start.ToArray();
Finish = finish.ToArray();
Flashlight = flashlight;
Message = message;
}
}
}
У меня нет реализации, но вот как работает решение:
Вы всегда отправляете самую быструю пару на другую сторону и возвращаете самую быструю на другую сторону, но вы никогда не отправляете одного и того же 2 раза (если только все не были отправлены 2 раза и тогда вы отправляете только самого быстрого, который прошел максимум 2 раза), помечая его (увеличивая его время на ад).
Это можно сделать с помощью 2 приоритетных очередей
s(O(n log) n
время решения).
Решение для вашего случая:
P-Q 1 P-Q 2 Buzz Woody Rex Hamm Buzz + Woody go = 10 min P-Q 1 P-Q 2 Rex Buzz Hamm Woody Buzz goes back = 5 min P-Q 1 P-Q 2 Hamm Woody Rex * Buzz Hamm + Rex go = 25 min P-Q 1 P-Q 2 * Buzz Woody Hamm Rex Woody comes back = 10 min P-Q 1 P-Q 2 * Buzz Hamm * Woody Rex Woddy + Buzz go = 10 min --------------------------- Total: 60 mins
Например, для 6 вариантов вы сделаете:
1 - fastest 2 - after fastest 3 - you got it 4 5 6 - slowest 1 + 2 go 1 goes back 3 + 4 go 2 goes back 5 + 6 go 3 goes back 1 + 2 go 1 goes back 1 + 3 go
Вы только что заставили меня узнать, как ужасно формы Я использую алгоритмы ИИ: (
Я всегда возвращался с самым быстрым парнем ... немного жульничал, но теперь я слишком устал, чтобы заставить его работать для всех комбинаций. Вот мое решение с использованием BFS.
class Program
{
private class Toy
{
public string Name { get; set; }
public int Time { get; set; }
}
private class Node : IEquatable<Node>
{
public Node()
{
Start = new List<Toy>();
End = new List<Toy>();
}
public Node Clone()
{
return new Node
{
Start = new List<Toy>(Start),
End = new List<Toy>(End),
Time = Time,
Previous = this
};
}
public int Time { get; set; }
public List<Toy> Start { get; set; }
public List<Toy> End { get; set; }
public Node Previous { get; set; }
public Toy Go1 { get; set; }
public Toy Go2 { get; set; }
public Toy Return { get; set; }
public bool Equals(Node other)
{
return Start.TrueForAll(t => other.Start.Contains(t)) &&
End.TrueForAll(t => other.End.Contains(t)) &&
Time == other.Time;
}
}
private static void GenerateNodes(Node node, Queue<Node> open, List<Node> closed)
{
foreach(var toy1 in node.Start)
{
foreach(var toy2 in node.Start.Where(t => t != toy1))
{
var newNode = node.Clone();
newNode.Start.Remove(toy1);
newNode.Start.Remove(toy2);
newNode.End.Add(toy1);
newNode.End.Add(toy2);
newNode.Go1 = toy1;
newNode.Go2 = toy2;
newNode.Time += Math.Max(toy1.Time, toy2.Time);
if(newNode.Time <= 60 && !closed.Contains(newNode) && !open.Contains(newNode))
{
open.Enqueue(newNode);
}
}
}
}
static void Main(string[] args)
{
var open = new Queue<Node>();
var closed = new List<Node>();
var initial = new Node
{
Start = new List<Toy>
{
new Toy {Name = "Buzz", Time = 5},
new Toy {Name = "Woody", Time = 10},
new Toy {Name = "Rex", Time = 20},
new Toy {Name = "Ham", Time = 25}
}
};
open.Enqueue(initial);
var resultNodes = new List<Node>();
while(open.Count != 0)
{
var current = open.Dequeue();
closed.Add(current);
if(current.End.Count == 4)
{
resultNodes.Add(current);
continue;
}
if(current.End.Count != 0)
{
var fastest = current.End.OrderBy(t => t.Time).First();
current.End.Remove(fastest);
current.Start.Add(fastest);
current.Time += fastest.Time;
current.Return = fastest;
}
GenerateNodes(current, open, closed);
}
foreach(var result in resultNodes)
{
var path = new List<Node>();
var node = result;
while(true)
{
if(node.Previous == null) break;
path.Insert(0, node);
node = node.Previous;
}
path.ForEach(n => Console.WriteLine("Went: {0} {1}, Came back: {2}, Time: {3}", n.Go1.Name, n.Go2.Name, n.Return != null ? n.Return.Name : "nobody", n.Time));
Console.WriteLine(Environment.NewLine);
}
Console.ReadLine();
}
}