DAG가 있습니다. 우리는 노드 (느슨하게 말해서 노드에 번호를 매 깁니다). 다음 규칙을 사용하여 새로운 방향 그래프를 작성하려고합니다.
- 동일한 번호의 노드 만 동일한 새 노드로 계약 할 수 있습니다. . (그러나 )
- 우리는 새로운 노드 사이에 모든 오래된 가장자리를 추가합니다 : .
- 이 새로운 그래프는 여전히 DAG입니다.
최소는 무엇입니까 ? 최소한의 새로운 그래프를 생성하는 알고리즘은 무엇입니까?
DAG가 있습니다. 우리는 노드 (느슨하게 말해서 노드에 번호를 매 깁니다). 다음 규칙을 사용하여 새로운 방향 그래프를 작성하려고합니다.
최소는 무엇입니까 ? 최소한의 새로운 그래프를 생성하는 알고리즘은 무엇입니까?
답변:
이 문제를 해결하는 한 가지 방법은 정수 선형 프로그래밍 (ILP)을 사용하는 것입니다. 문제의 의사 결정 버전을 해결해 봅시다. 가 주어지면 ≤ k 크기의 DAG를 얻기 위해 같은 색의 정점을 계약하는 방법이 있습니까?
이는 표준 기술을 사용하여 ILP 인스턴스로 표현 될 수 있습니다. 원래 그래프에서 각 정점의 색상이 주어집니다. 각 정점에 의 레이블로 레이블을 지정하는 것이 좋습니다 . 라벨과 색상이 같은 정점이 모두 계약됩니다. 따라서 의사 결정 문제는 다음과 같습니다. 모든 동일한 색상의 동일한 레이블 정점을 수축하면 DAG가 생성되도록 레이블이 있습니까?
정수 선형 프로그램으로이를 표현하기 위해 정수 변수 소개 각 꼭지점에 대한 V 정점에 라벨을 표현하기 위해, 절 . 부등식 1 ≤ ℓ v ≤ k를 더 합니다.
다음 단계는 계약 그래프가 DAG 여야한다는 요구 사항을 표현하는 것입니다. 공지 사항이 라벨은 계약 그래프의 위상 정렬 (유도 같은 라벨이 존재 일반성의 손실없이 위에 나열된 형태의 라벨,있는 경우 즉, 만약 선행 w 계약 그래프에서, 다음 V 의 라벨 w 의 레이블 보다 작습니다 ). 따라서 원래 그래프의 각 가장자리 v → w 에 대해 v 와 w 의 레이블과 색상이 동일하거나 v 의 레이블이 w 의 레이블 보다 작다 는 제약 조건을 추가합니다 . 구체적으로, 각 모서리 v 에 대해 초기 그래프 여기서 V , w는 동일한 색상을 가지고, 부등식 추가 ℓ의 V ≤ ℓ를 승 . 각 모서리 v → w 에 대해 v , w의 색상이 다른 경우 부등식 ℓ v < ℓ w를 추가하십시오.
이제이 정수 선형 프로그램에 적합한 솔루션이 있는지 확인하십시오. 라벨링이 원하는 형태 인 경우에만 가능한 해결책이있을 것입니다 (즉, 모든 동일한 색상의 동일한 라벨 정점을 계약하면 DAG가 생성됨). 다시 말해, 원래 그래프를 크기의 DAG로 계약하는 방법이있는 경우에만 가능한 해결책이있을 것 입니다. 정수 선형 프로그래밍 솔버를 사용할 수 있습니다. 만약 ILP 솔버가 우리에게 답을한다면, 우리는 원래의 결정 문제에 대한 답을 얻게됩니다.
물론 이것은 다항식 시간으로 완료한다고 보장 할 수 없습니다. 보장은 없습니다. 그러나 ILP 솔버는 꽤 좋아졌습니다. 합리적인 크기의 그래프의 경우 ILP 솔버가 적절한 시간 내에이 문제를 해결할 수있을 가능성이 높습니다.
이것을 SAT 인스턴스로 인코딩하고 SAT 솔버를 사용할 수도 있습니다. 그것이 더 효과적인지 모르겠습니다. 그래도 ILP 버전은 생각하기가 더 쉽습니다.
(이것이 옳기를 바랍니다. 모든 세부 사항을주의 깊게 확인하지 않았으므로 내 추론을 다시 확인하십시오!
업데이트 (10/21) :이 형식의 ILP는 DAG를 위상 적으로 정렬 된 순서로 처리하고 각 정점의 레이블에서 하한을 추적함으로써 선형 시간으로 해결할 수있는 것처럼 보입니다. 이것은 내 해결책을 의심합니다. 어딘가에서 실수를 했습니까?
참고 : AFAICT, DW 는이 축소에서 구멍을 발견했으며 잘못되었습니다 (주석 참조). 역사적인 이유로 여기에 보관하십시오.
소개 : 먼저 Monotone 3SAT 문제를 우리 문제로 줄입니다. 하지만 모노톤 3SAT의 문제가 하찮게 만족할 수있다, 우리의 문제는 더를 해결할 수 최소 진정한 모노톤 3SAT의 NP-어려운 문제; 따라서이 문제는 NP-hard입니다.
변수의 시퀀스와 절의 시퀀스로 표현되는 모노톤 부울 공식이 있습니다. CNF는 입니다.
및
그래프 합니다. G '의 각 정점 에는 레이블이 있습니다. 라벨이 같은 정점이 수축 될 수 있습니다.
다음 우선 그래프를 구성 : 각 , 우리는 두 개의 노드을 각각 표시된 x를 I , 다른 하나에서 유향 에지 (고해상도보기 이미지를 클릭).
이 노드들은 물론 동일한 레이블을 가지고 있기 때문에 수축 될 수 있습니다. 우리는 계약 된 변수 / 노드를 거짓으로 간주하고 계약되지 않은 변수 / 노드를 참으로 간주합니다 :
이 단계 후에 는 2 ⋅ | V | 노드. 다음으로 절 제약 조건을 소개합니다. 각 절에 대해, c i ∈ C , c i = ( x j ∨ x k ∨ x l ) | x j , x k , x l ∈ V , 우리는 하나의 노드 c i 와 다음 모서리를 소개합니다.
. (전체 이미지를 보려면 이미지를 클릭하십시오)
노드.
로 사이클이 발생합니다.
절 제약 조건을 풀면서 또 다른 시각화가 있습니다.
따라서 각 절 제약 조건에는 포함 된 변수 중 하나 이상이 계약되지 않은 상태로 유지되어야합니다. 계약되지 않은 노드는 true로 평가되므로 변수 중 하나가 true 여야합니다. Monotone SAT가 절에 요구하는 것.
모노톤 3SAT는 아주 만족 스럽습니다. 모든 변수를 true로 설정하면됩니다.
그러나 DAG 최소화 문제는 가장 많은 수축을 찾는 것이기 때문에 CNF에서 가장 잘못된 변수를 생성하는 만족스러운 할당을 찾는 것으로 해석됩니다. 최소 실제 변수를 찾는 것과 같습니다. 이 문제는 때때로 Minimum True Monotone 3SAT 또는 여기 (최적화 문제 또는 결정 문제) 또는 k-True Monotone 2SAT (약한 의사 결정 문제)라고합니다. NP- 하드 문제. 따라서 우리의 문제는 NP-hard입니다.
참고 문헌 :
그래프 소스 :
각 대체 (직 부모-자식 교체를 제외하고)와 함께 새로운 조상-하위 관계를 추가하여 장기적으로 실제로 어느 것이 가치가 있는지 결정하는 것은 사소하지 않습니다. 따라서 간단한 탐욕 알고리즘은 일반적인 경우 실패합니다. 그러나 무차별 대입 방식을 사용하는 경우 가장 작은 그래프를 결정할 수 있습니다.
Python-ish (테스트되지 않음) :
def play((V,E),F,sequence=[]):
"""
(V,E) -- a dag.
V -- a set of vertices.
E -- a set of directed-edge-tuples.
F -- a function that takes a vertex, returns an integer.
sequence -- the sequence of moved taken so far; starts with/defaults to
an empty list, will contain tuples of the form (x,y)
where x is removed and replaced with y.
Returns the best recursively found solution.
"""
#find all the integer values in the graph, remember which
# values correspond to what vertices. Of the form {integer => {vertices}}.
n2v = {}
for x in V:
n = F(x)
#for each integer, make sure you have a set to put the vertices in.
if n not in n2v:
n2v[n] = set()
#for each integer, add the vertex to the equivalent set.
n2v[n].add(v)
#record the best sequence/solution. You start with the current sequence,
# and see if you can obtain anything better.
best_solution = list(sequence)
#Now you will try to combine a single pair of vertices, obtain a new
# graph and then recursively play the game again from that graph.
#for each integer and equivalent set of vertices,
for n,vset in n2v.iteritems():
#pick a pair of vertices
for x in vset:
for y in vset:
#no point if they are the same.
if x == y:
continue
#If there is a path from x => y or y => x, then you will be
# introducing a cycle, breaking a rule. So in that case, disregard
# this pair.
#However, the exception is when one is a direct child of the other;
# in that case you can safely combine the vertices.
if pathtest((V,E),x,y) and (x,y) not in E and (x,y) not in E:
continue
#combine the vertices (function is defined below), discard x,
# replace it with y, obtain the new graph, (V',E').
Vp,Ep = combine_vertex((V,E),x,y))
#record the sequence for this move.
sequencep = list(sequence) + [(x,y)]
#recurse and play the game from this new graph.
solution = play(Vp,Ep,F,sequencep)
#if the returned solution is better than the current best,
if len(solution) > len(best_solution):
#record the new best solution
best_solution = solution
#return the best recorded solution
return best_solution
def combine_vertex((V0,E0),x,y):
"""
(V0,E0) -- an initial digraph.
V0 -- a set of vertices.
E0 -- a set of directed-edge-tuples.
x -- vertex to discard.
y -- vertex to replace it with.
returns a new digraph replacing all relationships to and from x to relate
to y instead, and removing x from the graph entirely.
"""
#the final vertex set will have everything except x
V = set(V0)
V.discard(x)
#now you construct the edge set.
E = set()
#for every edge,
for (u0,v0) in E0:
#recreate the edge in the new graph, but replace any occurence
# of x.
u,v = u0,v0
#if x is in the edge: replace it
if u == x:
u = y
if v == x:
v == y
#sometimes u=v=y and can now be pointing to itself, don't add that
# edge
if u == v:
continue
#add the new/replaced edge into the edge-set.
E.add( (u,v) )
return (V,E)
정말 어려운 문제인지 확실하지 않지만 일부 그래프를 수동으로 재생하면 매우 조합적인 것처럼 보입니다. 어려운 문제 가이 문제로 축소 될 수 있는지 또는 실행 시간이 더 좋은 알고리즘이 있는지 궁금합니다.