Неэкспоненциальное решение проблемы лабиринта?

Учитывая многокритериальный ациклический граф размером n * n, где каждый node имеет не более трех детей и трех родителей, существует ли неэкспоненциальный алгоритм для определения того, существует ли путь длины n, где ни один из двух узлов не разделяет то же значение, и каждое значение набора учитывается?

В принципе, у меня есть лабиринт n * n, где каждое пространство имеет случайное значение (1..n). Мне нужно найти путь (сверху вниз) из n узлов, который включает каждое значение.

В настоящий момент я использую поиск по глубине, но это T(n) = 3T(n-1) + O(1), который является O(3^n), неидеальным решением.

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

Изменить: чтобы сделать это немного более конкретным, вот лабиринт с решениями (решаемый с использованием решения глубины).

 1 2 5 5 4
 1 5 1 3 5
 4 1 2 3 2
 5 5 4 4 3
 4 2 1 2 4
S3, 5, 1, 3, 4, 2, F4
S3, 5, 1, 3, 4, 2, F2
S3, 5, 1, 3, 4, 2, F4
S3, 5, 3, 2, 4, 1, F3
S3, 5, 3, 2, 4, 1, F3
S3, 5, 3, 2, 4, 1, F3
S4, 5, 3, 2, 4, 1, F3
S4, 5, 3, 2, 4, 1, F3
S4, 5, 3, 2, 4, 1, F3
S4, 5, 1, 3, 4, 2, F4
S4, 5, 1, 3, 4, 2, F2
S4, 5, 1, 3, 4, 2, F4
S5, 4, 3, 2, 5, 1, F3
13 total paths`

Ответы

Ответ 1

Эта проблема NP-полная, и поэтому неизвестно, есть ли решение полиномиального времени. (Стандартные условия, возможно, легкие на практике и т.д., Все применимы.) Одно возможное сокращение - от 3SAT.

Предположим, что у нас есть экземпляр 3SAT, такой как (a ∨ b ∨ c) ∧ (¬a ∨ ¬b ∨ ¬c). Я покажу, как использовать "гаджеты" для создания экземпляра вашей проблемы. Прежде чем мы начнем, перепишите проблему 3SAT как (a1 ∨ b1 ∨ c1) ∧ (¬a2 ∨ ¬b2 ∨ ¬c2) вместе с a1 = a2, b1 = b2 и c1 = c2; то есть сделать каждое вхождение переменной уникальным, но затем добавить условие, что разные вхождения одной и той же переменной должны быть равны.

Во-первых, мы должны убедиться, что вы должны выбрать число 0 в первой строке, чтобы мы могли использовать его позже как "дозор", который вы должны избегать.

 0   0   0 

Теперь мы создаем гаджет, который применяет правило a1 = a2: (Подчеркнутый _ здесь - новый уникальный номер при каждом использовании этого гаджета)

 0   _   0 
 a1  0  ¬a1
 a2  0  ¬a2

Из-за первой строки вы должны избегать 0s. Это означает, что вы либо проходите путь "a1, a2", либо путь "¬a1, ¬a2"; первый будет соответствовать (слегка путающе), устанавливая значение a в false, в то время как последнее будет соответствовать настройке a в true. Это связано с тем, что гаджет нашей категории действительно прост, потому что мы просто записываем предложение, например. (снова _ здесь новая переменная каждый раз):

 0   _   0 
 a1  b1  b2

или

 0   _   0 
¬a1 ¬b1 ¬b2

Наконец, поскольку вы использовали только один из a1 и ¬a1 и т.д., мы позволяем вам брать те, которые вы не использовали свободно:

 0   _   0 
 a1 ¬a1  0 

Теперь это не совсем работает, потому что один из a1 и ¬a1 может быть использован в гаджете выбора переменных, в то время как другой может быть использован в предложении. Итак, мы включаем новую переменную @i для каждого предложения, которую вы можете взять вместо одной из переменных. Поэтому, если переменная a1 появляется в разделе 1, мы имеем

 0   _   0 
 a1 ¬a1  @1 

Здесь полный вывод перевода исходного предложения 3SAT (выделение пути, соответствующего установке a и b в true, c в false и выбор a из первого предложения), с числами слева и блеском на правильно. Гаджеты переупорядочиваются (гаджеты первого предложения, затем для каждой переменной, гаджет равенства и затем неиспользуемый гаджет), но это не имеет значения, так как они все равно независимы.

0       0  <    0               .       .  <    .       
0       8  <    0               .       _  <    .       
2  <    4       6               a1 <    b1      c1      
0       16 <    0               .       _       .       
11      13      15 <            -a2     -b2     -c2<    
0       17 <    0               .       _  <    .       
2       0       3  <            a1      .       -a1<    
10      0       11 <            a2      .       -a2<    
0       18 <    0               .       _  <    .       
2       3       1  <            a1      -a1     @1 <    
0       19 <    0               .       _       .       
10 <    11      9               a2 <    -a2     @2      
0       20 <    0               .       _  <    .       
4       0       5  <            b1      .       -b1<    
12      0       13 <            b2      .       -b2<    
0       21 <    0               .       _  <    .       
4  <    5       1               b1 <    -b1     @1      
0       22 <    0               .       _  <    .       
12 <    13      9               b2 <    -b2     @2      
0       23 <    0               .       _  <    .       
6  <    0       7               c1 <    .       -c1     
14 <    0       15              c2 <    .       -c2     
0       24 <    0               .       _  <    .       
6       7  <    1               c1      -c1<    @1      
0       25 <    0               .       _  <    .       
14      15      9  <            c2      -c2     @2 <    

(Если вы хотите, чтобы все было квадратным, просто включите кучу нулей в конце каждой строки.) Приятно видеть, что независимо от того, как вы решаете это, в глубине души вы решаете эту проблему 3SAT.

В конце моего сообщения есть поспешно написанная программа Perl, которая генерирует одну из ваших проблем из ввода формы

a b c
-a -b -c

Число переменных в результирующем экземпляре вашей проблемы - 11C + V + 1. Дайте программе переключатель -r для создания блеска вместо чисел.

# Set useful output defaults
$, = "\t"; $\ = "\n";

# Process readability option and force sentinel
my $r = "0";
if( $ARGV[0] =~ /-r/ ) { shift; $r = "."; }
print $r, $r, $r;

# Clause gadgets
my( %v, %c, $m, $c );
$m = 1;
while( <> ) {
    my( @v, @m );
    $c = $m++;
    chomp; @v = split;
    for my $v ( @v ) {
        push @{$v{strip($v)}}, -1; # hack, argh!
        push @m, ($r ? [email protected]{$v{strip($v)}} : $m + neg($v));
        $c{($r ? (strip($v)[email protected]{$v{strip($v)}}) : $m)} = $c;
        $v{strip($v)}->[-1] = ($r ? (strip($v)[email protected]{$v{strip($v)}}) : $m);
        $m += 2 unless $r;
    }
    print $r, newv(), $r;
    print @m;
}

# Variable gadget
for my $v ( sort keys %v ) {
    # Force equal
    print $r, newv(), $r;
    for my $n ( @{$v{$v}} ) {
        print $n, $r, ($r ? "-".$n : $n+1);
    }

    # Unused
    for my $n ( @{$v{$v}} ) {
        print $r, newv(), $r;
        print $n, ($r ? "-".$n : $n+1), ($r ? "\@".$c{$n} : $c{$n});
    }
}

# Strip leading -
sub strip {
    my( $v ) = @_;
    return substr $v, neg($v);
}

# Is this variable negative?
sub neg {
    my( $v ) = @_;
    return "-" eq substr( $v, 0, 1 );
}

# New, unused variable
sub newv {
    return "_" if $r;
    return $m++;
}

Ответ 2

Я уверен, что это можно сделать в полиномиальное время. Я бы начал с пустого набора, а затем прокрутил строки сверху вниз. Я собираюсь пропустить какой-либо код и показать вам, как будет выглядеть состояние на каждом шаге, и вы сможете составить алгоритм оттуда. Я уверен, что лучший случай немного хуже, чем O (n ^ 2), используя вариацию первого поиска ширины и отслеживание текущих хороших путей в таблице.

EDIT: Если это еще не достаточно быстро, вы можете улучшить его, применив оптимизацию Арлекина.

Пример:

1 2 3
3 2 1
1 2 1

Состояние 0:   R = 0//Строка   P = {}//Набор путей

// {{Path so far}, Column}

P' = {
    {{1}, 0}
    {{2}, 1}
    {{3}, 2}
}

P = P'

Состояние 1:   R = 1//ROW   P = {       {{1}, 0}       {{2}, 1}       {{3}, 2}   }

P' = {
    {{1 3}, 0}
    {{1 2}, 1}
    {{2 3}, 0}
    {{2 1}, 2}
    {{3 2}, 1}
    {{3 1}, 2}
}

Состояние 2:   R = 2   P = {       {{1 3}, 0}       {{1 2}, 1}       {{2 3}, 0}       {{2 1}, 2}       {{3 2}, 1}       {{3 1}, 2}   }

P' = {
    {{1 3 2}, 1}
    {{2 3 1}, 0}
    {{3 2 1}, 0}
    {{3 2 1}, 2}
    {{3 1 2}, 1}
}

Результат:
  Количество дорожек: 5
  S1 1 3 2 F2
  S2 2 3 1 F1
  S3 3 2 1 F1
  S3 3 2 1 F3
  S3 3 1 2 F2

Ответ 3

Вы можете попробовать ant оптимизация колоний. Он быстро дает очень хорошие результаты, которые очень близки к идеальным решениям.

Ответ 4

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

Пример. В примере 5x5, когда вы приходите в третью строку, третий столбец имеет три пути, ведущие к нему, которые содержат (1 2 5) в некотором порядке. Вы не должны следовать этим отдельно от этого момента, но можете объединить их. Если вы хотите узнать количество решений в конце, вам просто нужно настроить структуру данных пути, например. три (1 (1 2 5)) слились бы с (3 (1 2 5)).

Ответ 5

Найдите поиск A *. Это твой друг.