Пазл Мостовой переход - PullRequest
15 голосов
/ 17 июля 2009

Четверо мужчин должны пересечь мост ночью. Любая группа, пересекающая одного или двух человек, должна нести с собой фонарик. Фонарик должен идти вперед и назад; его нельзя бросить и т. д. Каждый человек ходит с разной скоростью. Один занимает 1 минуту, чтобы пересечь, еще 2 минуты, еще 5 и последние 10 минут. Если двое мужчин пересекаются вместе, они должны идти медленнее. Там нет никаких хитростей - все люди начинают с одной стороны, фонарик не может светить на большое расстояние, никто не может нести и т. Д.

И вопрос в том, что быстрее всего они могут пройти. Я в основном ищу какой-то обобщенный подход к такой проблеме. Мой друг сказал мне, что это можно решить с помощью ряда Фибоначчи, но решение не работает для всех.

Обратите внимание, что это не домашняя работа.

Ответы [ 11 ]

19 голосов
/ 17 июля 2009

Существует целый PDF ( альтернативная ссылка ), который решает общий случай этой проблемы (в формальном доказательстве).

13 голосов
/ 17 июля 2009

17 минут - это классический вопрос MS.

1,2 => 2 minutes passed.
1 retuns => 3 minutes passed.
5,10 => 13 minutes passed.
2 returns => 15 minutes passed.
1,2 => 17 minute passed.

В общем, самую большую проблему / самых медленных людей всегда следует объединять, и достаточно быстрых поездок, чтобы можно было каждый раз возвращать свет, не используя медленный ресурс.

12 голосов
/ 17 июля 2009

Я бы решил эту проблему, разместив поддельное объявление о работе на Dice.com, а затем задавая этот вопрос во время собеседований, пока кто-нибудь не поймет это правильно.

5 голосов
/ 08 августа 2013

Согласно Википедии

Загадка, как известно, появилась еще в 1981 году в книге «Супер стратегии для головоломок и игр». В этой версии головоломки А, В, С и D переходят через 5, 10, 20 и 25 минут соответственно, а ограничение по времени составляет 60 минут

Однако этот вопрос был популяризирован после его появления в книге «Как бы вы подвезли гору Фудзи?»

вопрос может быть обобщен для N человек с различным индивидуальным временем, необходимым для перехода через мост.

Данная программа работает для общего числа людей и их времени.

class Program
{
    public static int TotalTime(List<int> band, int n)
    {
        if (n < 3)
        {
            return band[n - 1];
        }
        else if (n == 3)
        {
            return band[0] + band[1] + band[2];
        }
        else
        {
            int temp1 = band[n - 1] + band[0] + band[n - 2] + band[0];
            int temp2 = band[1] + band[0] + band[n - 1] + band[1];

            if (temp1 < temp2)
            {
                return temp1 + TotalTime(band, n - 2);
            }
            else if (temp2 < temp1)
            {
                return temp2 + TotalTime(band, n - 2);
            }
            else
            {
                return temp2 + TotalTime(band, n - 2);
            }
        }
    }

    static void Main(string[] args)
    {
        // change the no of people crossing the bridge
        // add or remove corresponding time to the list
        int n = 4; 

        List<int> band = new List<int>() { 1, 2, 5, 10 };

        band.Sort();

        Console.WriteLine("The total time taken to cross the bridge is: " + Program.TotalTime(band, n));
        Console.ReadLine();
    }
}

ВЫВОД:

Общее время, необходимое для перехода через мост: 17

Для,

int n = 5; 
List<int> band = new List<int>() { 1, 2, 5, 10, 12 };

ВЫВОД:

Общее время, необходимое для перехода через мост: 25

Для

int n = 4; 
List<int> band = new List<int>() { 5, 10, 20, 25 };

ВЫХОД Общее время, необходимое для перехода через мост: 60

4 голосов
/ 08 ноября 2017

Еще одна реализация Ruby, вдохновленная решением @ roc-khalil

@values = [1,2,5,10]
# @values = [1,2,5,10,20,25]
@left = @values.sort
@right = []
@total_time = 0

def trace(moving)
  puts moving
  puts "State: #{@left} #{@right}"
  puts "Time: #{@total_time}"
  puts "-------------------------"
end

# move right the fastest two
def move_fastest_right!
  fastest_two = @left.shift(2)
  @right = @right + fastest_two
  @right = @right.sort
  @total_time += fastest_two.max
  trace "Moving right: #{fastest_two}"
end

# move left the fastest runner
def move_fastest_left!
  fastest_one = @right.shift
  @left << fastest_one
  @left.sort!
  @total_time += fastest_one
  trace "Moving left: #{fastest_one}"
end

# move right the slowest two
def move_slowest_right!
  slowest_two = @left.pop(2)
  @right = @right + slowest_two
  @right = @right.sort
  @total_time += slowest_two.max
  trace "Moving right: #{slowest_two}"
end

def iterate!
  move_fastest_right!
  return if @left.length == 0

  move_fastest_left!
  move_slowest_right!
  return if @left.length == 0

  move_fastest_left!
end

puts "State: #{@left} #{@right}"
puts "-------------------------"
while @left.length > 0
  iterate!
end

Выход:

State: [1, 2, 5, 10] []
-------------------------
Moving right: [1, 2]
State: [5, 10] [1, 2]
Time: 2
-------------------------
Moving left: 1
State: [1, 5, 10] [2]
Time: 3
-------------------------
Moving right: [5, 10]
State: [1] [2, 5, 10]
Time: 13
-------------------------
Moving left: 2
State: [1, 2] [5, 10]
Time: 15
-------------------------
Moving right: [1, 2]
State: [] [1, 2, 5, 10]
Time: 17
-------------------------
4 голосов
/ 07 ноября 2017

Вот ответ в рубине:

@values = [1, 2, 5, 10]
# @values = [1, 2, 5, 10, 20, 25, 30, 35, 40]
@values.sort!
@position = @values.map { |v| :first }
@total = 0

def send_people(first, second)
  first_time = @values[first]
  second_time = @values[second]

  @position[first] = :second
  @position[second] = :second

  p "crossing #{first_time} and #{second_time}"

  first_time > second_time ? first_time : second_time
end

def send_lowest
  value = nil
  @values.each_with_index do |v, i|
    if @position[i] == :second
      value = v
      @position[i] = :first
      break
    end
  end

  p "return #{value}"
  return value
end


def highest_two
  first = nil
  second = nil

  first_arr = @position - [:second]

  if (first_arr.length % 2) == 0
    @values.each_with_index do |v, i|
      if @position[i] == :first
        first = i unless first
        second = i if !second && i != first
      end

      break if first && second
    end
  else
    @values.reverse.each_with_index do |v, i|
      real_index = @values.length - i - 1
      if @position[real_index] == :first
        first = real_index unless first
        second = real_index if !second && real_index != first
      end

      break if first && second
    end
  end

  return first, second
end

#we first send the first two
@total += send_people(0, 1)
#then we get the lowest one from there
@total += send_lowest
#we loop through the rest with highest 2 always being sent
while @position.include?(:first)
  first, second = highest_two
  @total += send_people(first, second)
  @total += send_lowest if @position.include?(:first)
end

p "Total time: #{@total}"
2 голосов
/ 17 июля 2009

Исчерпывающий поиск всех возможностей прост с таким небольшим проблемным пространством. Ширина или глубина в первую очередь будет работать. Это простая проблема CS.

Я сам предпочитаю миссионерские и людоедские проблемы

1 голос
/ 28 июня 2018

Учитывая, что будет 2 стороны, сторона 1 и сторона 2, а число людей N должно пересекаться со стороны 1 на сторону 2. Логика пересечения моста ограничением числа людей L будет -

Шаг 1. Переместите число L самых быстрых членов со стороны 1 в сторону 2

Шаг 2: Верните самого быстрого человека из Стороны 2 в Сторону 1

Шаг 3: Переместите число L самых медленных членов со стороны 1 в сторону 2

Шаг 4: Верните самого быстрого человека из присутствующих в Сиде 2

Повторяйте эти шаги до тех пор, пока в стороне 1 не останется никого, ни в конце шага 2, ни в конце шага 4.

Код на C # для n человек, с двумя людьми одновременно, здесь. Это будет принимать N количество людей, которое может быть указано во время выполнения. Затем он примет имя человека и время, отведенное для N человек. Выходные данные также определяют итерацию минимально возможного времени.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RiverCrossing_Problem
{
    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<string, int> Side1 = new Dictionary<string, int>();
            Dictionary<string, int> Side2 = new Dictionary<string, int>();

            Console.WriteLine("Enter number of persons");
            int n = Convert.ToInt32(Console.ReadLine());

            Console.WriteLine("Enter the name and time taken by each");

            for(int a =0; a<n; a++)
            {
                string tempname = Console.ReadLine();
                int temptime = Convert.ToInt32(Console.ReadLine());
                Side1.Add(tempname, temptime);
            }

            Console.WriteLine("Shortest time and logic:");
            int totaltime = 0;
            int i = 1;
            do
            {
                KeyValuePair<string, int> low1, low2, high1, high2;
                if (i % 2 == 1)
                {
                    LowestTwo(Side1, out low1, out low2);
                    Console.WriteLine("{0} and {1} goes from side 1 to side 2, time taken = {2}", low1.Key, low2.Key, low2.Value);
                    Side1.Remove(low2.Key);
                    Side1.Remove(low1.Key);
                    Side2.Add(low2.Key, low2.Value);
                    Side2.Add(low1.Key, low1.Value);
                    totaltime += low2.Value;

                    low1 = LowestOne(Side2);
                    Console.WriteLine("{0} comes back to side 1, time taken = {1}", low1.Key, low1.Value);
                    totaltime += low1.Value;
                    Side1.Add(low1.Key, low1.Value);
                    Side2.Remove(low1.Key);
                    i++;
                }
                else
                {
                    HighestTwo(Side1, out high1, out high2);
                    Console.WriteLine("{0} and {1} goes from side 1 to side 2, time taken = {2}", high1.Key, high2.Key, high1.Value);
                    Side1.Remove(high1.Key);
                    Side1.Remove(high2.Key);
                    Side2.Add(high1.Key, high1.Value);
                    Side2.Add(high2.Key, high2.Value);
                    totaltime += high1.Value;

                    low1 = LowestOne(Side2);
                    Console.WriteLine("{0} comes back to side 1, time taken = {1}", low1.Key, low1.Value);
                    Side2.Remove(low1.Key);
                    Side1.Add(low1.Key, low1.Value);
                    totaltime += low1.Value;
                    i++;
                }
            } while (Side1.Count > 2);

            KeyValuePair<string, int> low3, low4;
            LowestTwo(Side1, out low3, out low4);
            Console.WriteLine("{0} and {1} goes from side 1 to side 2, time taken = {2}", low3.Key, low4.Key, low4.Value);
            Side2.Add(low4.Key, low4.Value);
            Side2.Add(low3.Key, low3.Value);
            totaltime += low4.Value;

            Console.WriteLine("\n");
            Console.WriteLine("Total Time taken = {0}", totaltime);

        }

        public static void LowestTwo(Dictionary<string, int> a, out KeyValuePair<string, int> low1, out KeyValuePair<string, int> low2)
        {
            Dictionary<string, int> b = a;
            low1 = b.OrderBy(kvp => kvp.Value).First();
            b.Remove(low1.Key);
            low2 = b.OrderBy(kvp => kvp.Value).First();
        }

        public static void HighestTwo(Dictionary<string,int> a, out KeyValuePair<string,int> high1, out KeyValuePair<string,int> high2)
        {
            Dictionary<string, int> b = a;
            high1 = b.OrderByDescending(k => k.Value).First();
            b.Remove(high1.Key);
            high2 = b.OrderByDescending(k => k.Value).First();
        }

        public static KeyValuePair<string, int> LowestOne(Dictionary<string,int> a)
        {
            Dictionary<string, int> b = a;
            return b.OrderBy(k => k.Value).First();
        }
    }
}

Пример вывода при случайном вводе, который в данном случае равен 7, и 2 человека для пересечения одновременно будут:

Enter number of persons
7
Enter the name and time taken by each
A
2
B
5
C
3
D
7
E
9
F
4
G
6
Shortest time and logic:
A and C goes from side 1 to side 2, time taken = 3
A comes back to side 1, time taken = 2
E and D goes from side 1 to side 2, time taken = 9
C comes back to side 1, time taken = 3
A and C goes from side 1 to side 2, time taken = 3
A comes back to side 1, time taken = 2
G and B goes from side 1 to side 2, time taken = 6
C comes back to side 1, time taken = 3
A and C goes from side 1 to side 2, time taken = 3
A comes back to side 1, time taken = 2
A and F goes from side 1 to side 2, time taken = 4


Total Time taken = 40
1 голос
/ 17 июля 2009

17 - очень распространенный вопрос

-> 1-2 = 2
<- 2 = 2 <br> -> 5,10 = 10 (никто из них не должен возвращаться)
<- 1 = 1 <br> -> 1,2 = 2

все на другой стороне
всего = 2 + 2 + 10 + 1 + 2 = 17

обычно люди получают это как 19 с первой попытки

0 голосов
/ 14 декабря 2016

Простой алгоритм: предположим, что «N» - это количество людей, которые могут пересечь одновременно, и один человек должен пересечь назад с факелом

  1. При перемещении людей с первой стороны на вторую сторону предпочтение следует отдавать самым медленно идущим 'N'
  2. Всегда используйте самый быстрый ходок, чтобы поднять факел со второй стороны на первую сторону
  3. При перемещении людей с первой стороны на вторую принимайте во внимание, кто вернет факел на следующем шаге. Если скорость носителя факела на следующем шаге будет равна самой быстрой ходунке, среди «N» самых медленных ходунков, на текущем шаге, то вместо выбора «N» самой медленной ходунки, как указано в «1», выберите «N» 'самые быстрые ходоки

Вот пример скрипта Python, который делает это: https://github.com/meowbowgrr/puzzles/blob/master/bridgentorch.py

...