하스켈, 278 자
(∈)=elem
r v[][]=[(>>=(++" ").show.fromEnum.(∈v))]
r v[]c@(a:b:_)=r(a:v)c[]++r(-a:v)c[]++[const"UNSOLVABLE"]
r v(a:b:c)d|a∈v||b∈v=r v c d|(-a)∈v=i b|(-b)∈v=i a|1<3=r v c(a:b:d)where i w|(-w)∈v=[]|1<3=r(w:v)(c++d)[]
t(n:_:c)=(r[][]c!!0)[1..n]++"\n"
main=interact$t.map read.words
무차별적인 힘. 다항식 시간으로 실행됩니다. 어려운 문제 (60 개의 변수, 99 개의 절)를 빠르게 해결합니다.
> time (runhaskell 1933-2Sat.hs < 1933-hard2sat.txt)
1 1 1 0 0 0 0 0 0 1 1 0 0 1 0 1 1 1 0 1 1 0 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 0 0 1 0 1 1 1 1 0
real 0m0.593s
user 0m0.502s
sys 0m0.074s
실제로 대부분의 시간은 코드를 컴파일하는 데 소비됩니다!
테스트 케이스 및 빠른 검사 테스트가 가능한 전체 소스 파일 .
Ungolf'd :
-- | A variable or its negation
-- Note that applying unary negation (-) to a term inverts it.
type Term = Int
-- | A set of terms taken to be true.
-- Should only contain a variable or its negation, never both.
type TruthAssignment = [Term]
-- | Special value indicating that no consistent truth assignment is possible.
unsolvable :: TruthAssignment
unsolvable = [0]
-- | Clauses are a list of terms, taken in pairs.
-- Each pair is a disjunction (or), the list as a whole the conjuction (and)
-- of the pairs.
type Clauses = [Term]
-- | Test to see if a term is in an assignment
(∈) :: Term -> TruthAssignment -> Bool
a∈v = a `elem` v;
-- | Satisfy a set of clauses, from a starting assignment.
-- Returns a non-exhaustive list of possible assignments, followed by
-- unsolvable. If unsolvable is first, there is no possible assignment.
satisfy :: TruthAssignment -> Clauses -> [TruthAssignment]
satisfy v c@(a:b:_) = reduce (a:v) c ++ reduce (-a:v) c ++ [unsolvable]
-- pick a term from the first clause, either it or its negation must be true;
-- if neither produces a viable result, then the clauses are unsolvable
satisfy v [] = [v]
-- if there are no clauses, then the starting assignment is a solution!
-- | Reduce a set of clauses, given a starting assignment, then solve that
reduce :: TruthAssignment -> Clauses -> [TruthAssignment]
reduce v c = reduce' v c []
where
reduce' v (a:b:c) d
| a∈v || b∈v = reduce' v c d
-- if the clause is already satisfied, then just drop it
| (-a)∈v = imply b
| (-b)∈v = imply a
-- if either term is not true, the other term must be true
| otherwise = reduce' v c (a:b:d)
-- this clause is still undetermined, save it for later
where
imply w
| (-w)∈v = [] -- if w is also false, there is no possible solution
| otherwise = reduce (w:v) (c++d)
-- otherwise, set w true, and reduce again
reduce' v [] d = satisfy v d
-- once all caluses have been reduced, satisfy the remaining
-- | Format a solution. Terms not assigned are choosen to be false
format :: Int -> TruthAssignment -> String
format n v
| v == unsolvable = "UNSOLVABLE"
| otherwise = unwords . map (bit.(∈v)) $ [1..n]
where
bit False = "0"
bit True = "1"
main = interact $ run . map read . words
where
run (n:_:c) = (format n $ head $ satisfy [] c) ++ "\n"
-- first number of input is number of variables
-- second number of input is number of claues, ignored
-- remaining numbers are the clauses, taken two at a time
golf'd 버전, satisfy및 format로 압연 된 reduce피 전달하기 위해서이지만 n, reduce변수 (목록에서 함수를 리턴 [1..n]스트링 결과로).
- 편집 : (330-> 323)
s연산자를 사용하여 줄 바꿈을보다 잘 처리했습니다.
- 편집 : (323-> 313) 게으른 결과 목록의 첫 번째 요소가 사용자 정의 단락 연산자보다 작습니다.
∮연산자로 사용 하는 것이 좋기 때문에 메인 솔버 기능의 이름이 바뀌 었습니다 !
- 편집 : (313-> 296) 절을 목록 목록이 아닌 단일 목록으로 유지하십시오. 한 번에 두 가지 요소를 처리
- 편집 : (296-> 291) 두 상호 재귀 함수를 병합; 인라인하는 것이 더 저렴해서
★테스트 이름이 바뀌 었습니다.∈
- 편집 : 결과 생성에 (291-> 278) 인라인 출력 형식