Эта проблема является 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
Из-за первой строки вы должны избегать нулей. Это означает, что вы либо выбираете путь "a1, a2" или путь "¬a1, ¬a2"; первый будет соответствовать (слегка сбивающему с толку) значению a, а второй будет соответствовать значению a. Это связано с тем, что наш гаджет предложения действительно прост, потому что мы просто записываем предложение, например (снова _
здесь каждый раз новая переменная):
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 ? $v.@{$v{strip($v)}} : $m + neg($v));
$c{($r ? (strip($v).@{$v{strip($v)}}) : $m)} = $c;
$v{strip($v)}->[-1] = ($r ? (strip($v).@{$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++;
}