2009-02-11 2 views
14

Учитывая многокритериальный ациклический граф размером n в n, где каждый узел имеет не более трех детей и трех родителей, существует ли неэкспоненциальный алгоритм для определения того, существует ли путь длины 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`
+0

следует ли это помечать как домашнюю работу? –

+0

Это не то, что я прошу «код, kthxbye». В рамках более масштабного программирования я столкнулся с проблемой, и мне интересно, выполнил ли я наилучшую работу, или если я буду придерживаться головы в CLRS и Knuth в течение еще нескольких часов и посмотреть, «Что-то не хватает. –

+0

Кроме того, формулировка - все мое. Нам было дано наивное описание, которое я обобщил во втором абзаце. –

ответ

11

Эта проблема 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: (The подчеркивание _ здесь новый уникальный номер, в каждом использовании этого гаджета)

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 (выделив путь, соответствующий настройке а и Ь истинно, с к ложным, и выбирая из первого предложения), с цифрами слева и с блеском справа.Гаджеты переупорядочиваются (гаджеты первого предложения, затем для каждой переменной, гаджет равенства и затем неиспользуемый гаджет), но это не имеет значения, так как они независимы в любом случае.

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++; 
} 
+0

Это действительно сложно, и я не уверен, как он сопоставляется с оригинальной постановкой задачи. – FryGuy

+2

@FryGuy: Первоначальный вопрос заключался в том, было ли субэкспоненциальное решение проблемы «лабиринта». Если бы это было так, то это перевело бы на один для 3SAT путем сокращения выше. Поскольку в настоящее время это открытая проблема, это будет большим прорывом. Вам неудобно доказательство? –

+2

Мне комфортно с доказательствами, я просто ошибся в ее чтении и думал, что у тебя странная нотация. Я думал, что вы собираетесь решать задачу Maze, используя экземпляр 3-SAT, вместо того, чтобы решать 3-SAT с помощью Maze-Problem. Второй абзац может быть более четким. – FryGuy

5

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

EDIT: Если это еще не достаточно быстро, вы можете улучшить его, применив Harlequin's optimization.

Например:

Состояние 0: R = 0 // Строка Р = {} // Путь Set

// {{Path so far}, Column} 

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

P = P' 

Состояние 1: R = 1 // СТРОКА Р = { {{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 Р = { {{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 2 3 F2
S2 2 3 1 F1
S3 3 2 1 F1
S3 3 2 1 F3
S3 3 1 2 F2

+1

+1, предполагая, что это на самом деле дерево. Если это actully чересчурный ациклический граф, или еще лучше лабиринт с циклами, и все это становится более интересным. Интересно, правильно ли задан вопрос? –

+0

Циклы не проблема, это огромное количество возможных путей. Добавлены некоторые данные, потому что я, возможно, неправильно задал вопрос. –

+0

@ Кевин, работаю ли я с головы или листа, разве у меня еще нет производительности T (n) = 3T (n-1)? –

0

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

+0

A * для кратчайший путь думаю. Ему нужен путь, который посещает все узлы от 1 до n только один раз. – Staale

+0

Учитывая, что расстояние фиксировано, и изменения весов (от 0 до inf) на основе ранее посещенных узлов, A * было бы очень сложно применить. –

3

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

1

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

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

Смежные вопросы