Tìm các hàng làm cho mỗi cột có một True (là: Thuật toán Knuth's X)


8

Bài tập

Đưa ra một ma trận Boolean, tìm một (hoặc tùy chọn nhiều hơn) tập hợp con của các hàng có chính xác một True trong mỗi cột. Bạn có thể sử dụng bất kỳ thuật toán nào , nhưng phải hỗ trợ các ma trận rất lớn, như ví dụ trước.

Một thuật toán có thể (Thuật toán Knuth X )

Mặc dù không có yêu cầu sử dụng thuật toán này, nó có thể là lựa chọn tốt nhất của bạn.

  1. Nếu ma trận A không có cột, giải pháp một phần hiện tại là một giải pháp hợp lệ; chấm dứt thành công.
  2. Nếu không thì chọn một cột c .
  3. Chọn * một hàng r sao cho A r , c = 1.
  4. Bao gồm hàng r trong giải pháp một phần.
  5. Đối với mỗi cột jA r , j = 1,
     cho mỗi hàng i như rằng A i , j = 1,
      xóa hàng i từ ma trận A .
     cột xóa j từ ma trận A .
  6. Lặp lại thuật toán này một cách đệ quy trên ma trận giảm Một .

* Bước 3 là không xác định và cần phải quay lại trong trường hợp không tìm thấy một hàng trong lệnh gọi sau của bước 3.

Đầu vào

Bất kỳ đại diện mong muốn nào của ma trận 2 × 2 tối thiểu A , ví dụ như là một mảng số hoặc Boolean

1 0 0 1 0 0 1
1 0 0 1 0 0 0
0 0 0 1 1 0 1
0 0 1 0 1 1 0
0 1 1 0 0 1 1
0 1 0 0 0 0 1

hoặc như bộ sưu tập Universe + Set

U = {1, 2, 3, 4, 5, 6, 7}
S = {
    A = [1, 4, 7],
    B = [1, 4],
    C = [4, 5, 7],
    D = [3, 5, 6],
    E = [2, 3, 6, 7],
    F = [2, 7]
    }

hoặc là 0 hoặc 1 bộ được lập chỉ mục; {{1, 4, 7}, {1, 4}, {4, 5, 7}, {3, 5, 6}, {2, 3, 6, 7}, {2, 7}}.

Đầu ra

Bất kỳ đại diện mong muốn nào của một (hoặc tùy chọn nhiều hơn / tất cả) các giải pháp, ví dụ như mảng số hoặc Boolean của các hàng đã chọn

1 0 0 1 0 0 0
0 0 1 0 1 1 0
0 1 0 0 0 0 1

hoặc dưới dạng danh sách Boolean cho biết các hàng đã chọn {0, 1, 0, 1, 0, 1}hoặc dưới dạng danh sách số (0 hoặc 1 được lập chỉ mục) của các hàng được chọn {2, 4, 6}hoặc dưới dạng danh sách tên đã đặt ['B', 'D', 'F'].

Thêm ví dụ

Trong:

1 0 1
0 1 1
0 1 0
1 1 1

Out: 1 3 hay 4hay 1 0 1 0hay 0 0 0 1hay [[1,3],[4], vv


Trong:

1 0 1 0 1
0 1 0 1 0
1 1 0 0 1
0 1 0 1 1

Out: 1 1 0 0 vv


Trong:

0 1 0 1 1 0 1
1 1 0 0 1 1 1
0 1 0 0 1 0 0
1 1 1 0 0 0 1
0 0 0 1 1 1 0

Out: 0 0 0 1 1 vv


Trong:

0 1 1
1 1 0

Hết: Không có gì hoặc lỗi hoặc giải pháp bị lỗi, tức là bạn không phải xử lý các đầu vào không có giải pháp.


Trong: http://pastebin.com/raw/3GAup0fr

Ngoài: 0 10 18 28 32 38 48 61 62 63 68 86 90 97 103 114 120 136 148 157 162 174 177 185 186 194 209 210 218 221 228 243 252 255 263 270 271 272 273 280 291 294 295 309 310 320 323 327 339 345 350 353 355 367 372 373 375 377 382 385 386 389 397 411 417 418 431 433 441 451 457 458 459 466 473 479 488 491 498 514 517


Trong: https://gist.github.com/angs/e24ac11a7d7c63d267a2279d416bc694

Ngoài: 553 2162 2710 5460 7027 9534 10901 12281 12855 13590 14489 16883 19026 19592 19834 22578 25565 27230 28356 29148 29708 30818 31044 34016 34604 36806 36918 39178 43329 43562 45246 46307 47128 47906 48792 50615 51709 53911 55523 57423 59915 61293 62087 62956 64322 65094 65419 68076 70212 70845 71384 74615 76508 78688 79469 80067 81954 82255 84412 85227


4
" Chỉ các giải pháp sử dụng thuật toán này mới đủ điều kiện để giành chiến thắng " nhưng chính xác những gì được tính là " thuật toán này "? Làm thế nào theo nghĩa đen là cần thiết để " xóa hàng " và " xóa cột "? Và thuật toán có phải sử dụng heuristic, một phần quan trọng trong phần trình bày thuật toán của Knuth nhưng không được đề cập ở tất cả trong mô tả của bạn không?
Peter Taylor

6
Có thể tốt hơn để đưa ra một câu hỏi chỉ yêu cầu trang bìa chính xác nhưng có một số trường hợp kiểm tra nặng không thể xử lý bằng lực lượng vũ phu ngây thơ nhưng có thể được xử lý bằng thuật toán của Knuth.
Peter Taylor


1
Tất cả các thuật toán bây giờ được cho phép như nhau.
Adám

1
"Phải hỗ trợ các ma trận rất lớn" khá mơ hồ, đặc biệt vì thuật toán của Knuth không thể xử lý trường hợp thử nghiệm lớn mà không có lựa chọn heuristic. Có thể có câu hỏi này là mã golf thuần túy và có câu hỏi khác là mã nhanh nhất ?
Angs

Câu trả lời:


5

Haskell, 100 93 92 87 83 80 byte

Thuật toán của Knuth:

g&c=filter(g.any(`elem`c))
(u:v)%a=[c:s|c<-id&u$a,s<-(not&c)v%(not&c$a)]
x%_=[x]

Tính toán tất cả các bìa không có chiều sâu đầu tiên trong danh sách đơn nguyên. Sử dụng headđể tính toán chỉ một vì Haskell lười biếng. Sử dụng:

*Main> [[1],[2],[3],[4],[5],[6],[7]]%[[1, 4, 7], [1, 4], [4, 5, 7], [3, 5, 6], [2, 3, 6, 7], [2, 7]]
[[[1,4],[2,7],[3,5,6]]]

Để có thêm tốc độ bằng cách sử dụng đề xuất của Knuth về việc chọn cột có ít cột nhất, hãy sử dụng mục này: (115 byte, danh sách phẳng cho vũ trụ). Tìm giải pháp đầu tiên cho vấn đề che phủ pentomino lớn trong vòng một phút khi được biên dịch.

import Data.List
[]%_=[[]]
w%a=[c:s|c<-a,c\\(head.sortOn length.group.sort$w:a>>=id)/=c,s<-(w\\c)%[b|b<-a,c\\b==c]]

Cảm ơn @Zgarb vì đã tiết kiệm 1 + 3 byte!

Cảm ơn @ChristianSievers vì lời khuyên hiền triết của anh ấy và tiết kiệm 5 byte và một số.

Ungolfed (với danh sách vũ trụ phẳng):

knuthX [] _ = [[]]
knuthX (u:niverse) availableRows = --u chosen deterministically
  [ chosen:solution
  | let rows = filter (elem u) availableRows
  , chosen <- rows  --row chosen nondeterministically in list monad
  , solution <- knuthX
                  (filter (not.(`elem`chosen)) niverse)
                  (filter (not.any(`elem`chosen)) availableRows)
  ]

Có thể đáng để thêm một số lời giải thích về cách nó hoạt động cho những người không quen thuộc với Haskell. Bạn đang sử dụng danh sách đơn nguyên để xử lý sự không phổ biến, tôi nghĩ vậy?

Bạn có thể lưu 3 byte bằng cách thay đổi filterthành một danh sách hiểu và xác định một chức năng phụ trợ h!x=h(`elem`(x>>=id)).
Zgarb

1
@ChristianSievers Tôi đang chạy vào giới hạn đơn hình với (!)=elem, do đó a, là. Và vâng, f chắc chắn có thể được sử dụng ở đó. Cảm ơn! Các kết hợp khác nhau của filter … elemcầu xin được thống nhất
Angs

1
Chúng ta có thể quay trở lại vũ trụ phẳng, sử dụng phiên bản thường sẽ nhanh hơn nhưng không có sự khác biệt trong ví dụ lớn và lưu một số byte bằng cách sử dụng w%a=[c:s|(u:_)<-[sortOn length.group.sort$w++concat a],c<-id&u$a,s<-(w\\c)%(not&c$a)]. Lưu ý rằng bây giờ ulà một danh sách có thể chứa cột được chọn nhiều lần, nhưng điều đó không quan trọng cho tính chính xác.
Christian Sievers

1
@ChristianSievers hooray, chiều dài ít hơn + 50% từ chậm đến nhanh! Có một sự hồi quy nhỏ về tốc độ khi uđược nội tuyến vì nó được tính một lần cho mỗi phần tử a, nhưng chúng tôi đang hướng tới tốc độ chơi gôn chứ không phải tốc độ tối ưu. c\\b==ccó lẽ không tệ vì nó có thể dừng lại một cách lười biếng. Không nội tuyến uvà sử dụng Data.Map.Strictđể tìm phần tử hiếm nhất sẽ ở một cấp độ hoàn toàn khác.
Angs

1

Python, 482 byte

r=lambda X,Y:u({j:set(filter(lambda i:j in Y[i],Y))for j in X},Y)
def u(X,Y,S=[]):
 if X:
  for r in list(X[min(X,key=lambda c:len(X[c]))]):
   S.append(r);C=v(X,Y,r)
   for s in u(X,Y,S):yield s
   w(X,Y,r,C);S.pop()
 else:yield list(S)
def v(X,Y,r):
 C=[]
 for j in Y[r]:
  for i in X[j]:
   for k in Y[i]:
    if k!=j:X[k].remove(i)
  C.append(X.pop(j))
 return C
def w(X,Y,r,C):
 for j in reversed(Y[r]):
  X[j]=C.pop()
  for i in X[j]:
   for k in Y[i]:
    if k!=j:X[k].add(i)

r là chức năng gọi với bộ sưu tập Universe + Set.

Chơi gôn một chút từ trang này

Sử dụng:

X = {1, 2, 3, 4, 5, 6, 7}
Y = {
    'A': [1, 4, 7],
    'B': [1, 4],
    'C': [4, 5, 7],
    'D': [3, 5, 6],
    'E': [2, 3, 6, 7],
    'F': [2, 7]}

for a in r(X,Y): print a

Bạn sẽ có thể loại bỏ các diễn viên listtrong vòng lặp đầu tiên và sản lượng, và thay đổi reversed(...)thành...[::-1]
Blue

Mỗi khi bạn sử dụng, S.append(x)bạn có thể làm S+=x,(với dấu phẩy): chẳng hạn C+=X.pop(j),.
FlipTack

1

R, 124 117 115 113 byte

Rất không hiệu quả, nhưng mã đó không dài. Thử tất cả các tập hợp con có thể của các hàng và kiểm tra nếu tất cả các hàng có tổng bằng 1.

f=function(x,n=nrow(x))for(i in 1:n)for(j in 1:ncol(z<-combn(n,i)))if(all(colSums(x[k<-z[,j],,drop=F])==1))cat(k)

Lấy một ma trận làm đầu vào. Trả về các rownumbers của giải pháp đầu tiên gặp phải. Trả về không có gì nếu không có giải pháp, nhưng có thể mất nhiều thời gian trong khi chấm dứt nếu đầu vào lớn.

Ung dung:

f=function(x, n=nrow(x)){


    for(i in 1:n){
        z=combn(n,i)

        for(j in 1:ncol(z)){
            k=x[z[,j],,drop=F]

            if(all(colSums(k)==1)){
                print(z[,j])
            }
        }
    }
}

7 byte được lưu nhờ Billywob

2 byte khác được lưu nhờ Billywob


Cảm ơn, tôi không biết bạn có thể gán biến nội tuyến như thế. Ngoài ra, nếu bạn bỏ drop=Fcâu lệnh, nó không hoạt động đối với các tập hợp con chỉ có một hàng. Tôi chưa bao giờ làm việc với scantrước đây và chỉ cho rằng nó sẽ hoạt động như vậy, xấu của tôi. Thay đổi nó thành một chức năng được đặt tên.
JAD

Cũng thay đổi đầu ra để trả về các chỉ số của giải pháp, tiết kiệm thêm 2 byte.
JAD

Nói chung, bạn không cần sử dụng các hàm được đặt tên (trừ khi chúng được lồng nhau). Ngoài ra, nếu bạn gán bộ đếm hàng làm đối số ngầm cho hàm, bạn lại có thể bỏ qua dấu ngoặc nhọn:function(x,n=nrow(x))for(i in 1:n)for(j in 1:ncol(z<-combn(n,i)))if(all(colSums(x[k<-z[,j],,drop=F])==1))cat(k)
Billywob

À đúng rồi, tôi nghĩ về việc đó với nnhưng không hiểu sao nó lại trượt tâm trí tôi. Cảm ơn một lần nữa :)
JAD

0

APL (Dyalog) , 81 byte

{×≢⍉⍵:⍵∇{~1∊⍵:00s←⍺⍺c/⍺⌿⍨r←~∨/⍺/⍨~c←~,⍺⌿⍨f←<\⍵:⍺∇f<⍵⋄fr\s},⍵/⍨<\n=⌊/n←+⌿⍵⋄∧/⍵}

Hãy thử trực tuyến!

{ chức năng ẩn danh:

: nếu…

   Nếu tranh luận

   khi hoán vị

   có số lượng hàng

  × đó là tích cực

 sau đó

  ⍵∇{Sau đó, áp dụng hàm này với đối số bên phải là đối số bên trái (ma trận ràng buộc), nhưng chỉ sau khi nó được sửa đổi bởi toán tử ẩn danh sau (hàm bậc cao hơn):
   : nếu
    1∊⍵ có một đối số trong đối số bên phải    thì
    ~ KHÔNG  trả về 0 (tức là không thành công)  :  if,  điều đúng đầu tiên của đối số bên phải (lit. tích lũy nhỏ hơn; hàng đầu tiên)  gán điều đó cho f  sử dụng để lọc các hàng của  ravel đối số bên trái (flatten)  phủ  định gán điều đó cho c  phủ định  sử dụng điều đó để lọc các cột của đối số bên trái  mà các hàng có đúng không? (HOẶC giảm)  phủ nhận rằng

    0
   
   :
    <\⍵
    f←
    ⍺⌿⍨
    ,
    ~
    c←
    ~
    ⍺/⍨
    ∨/
    ~
    ⍺⌿⍨ sử dụng để lọc các hàng của trái lập luận
    c/ sử dụng c để lọc các cột đó
    ⍺⍺ áp dụng các chức năng bên ngoài ban đầu (các toán hạng bên trái; bìa tiểu ma trận)
    s← assign đó để s
    0≡  ... giống hệt như zero (thất bại), sau đó (thử một hàng khác nhau):
    f<⍵ phải tranh luận VÀ KHÔNG f
    ⍺∇  recurse trên đó (giữ lập luận ban đầu trái)
    khác:
    r\s số không sử dụng trong r để chèn zero-điền cột trong s
    f∨  trở lại f HOẶC đó (thành công; hàng f bao gồm)
  }... ... trên

  +⌿⍵ tổng của đối số

  n← gán nó cho n

  ⌊/ mức tối thiểu đó

  n= Boolean trong đó n bằng

  <\ cái đầu tiên trong số đó (ít hơn tích lũy)

  ⍵/⍨ sử dụng điều đó để lọc các cột của đối số (đưa ra cột đầu tiên có ít cột nhất)

  , cái rốn đó (làm phẳng)

 khác

  ∧/⍵ các hàng là tất cả các hàng (không có, vì vậy điều này cho số không cho mỗi hàng)

} kết thúc chức năng ẩn danh

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.