Tìm hình chữ nhật có thể có


8

Johnny đang cố gắng tạo ra các trò chơi ô chữ, nhưng anh ta gặp khó khăn trong việc tạo ra các từ khớp với nhau.

Ông đã đưa ra một số hình chữ nhật từ đơn giản: đó là các nhóm từ tạo thành một hình chữ nhật trong đó tất cả các đường ngang và dọc tạo thành một từ.

//2x2 
PA
AM

//2x3
GOB
ORE

//3x3
BAG
AGO
RED

//3x4
MACE
AGES
WEES

Tuy nhiên, để tạo ra một câu đố hay, anh ta cần một số hình chữ nhật có kích thước lớn hơn 3x4. Thay vì đau đớn trong việc sắp xếp các chữ cái trong nhiều giờ, Johnny thích có một chương trình thực hiện điều này cho anh ta - và trong càng ít nhân vật càng tốt, bởi vì các khối mã dài cực kỳ đáng sợ đối với các lập trình viên bình thường như Johnny.


Được

  • một từ điển tệp văn bản nơi các từ được phân tách bằng các dòng mới theo thứ tự bảng chữ cái,
  • đầu vào chỉ định số lượng hàng và cột trong hình chữ nhật từ (có thể được cung cấp tuy nhiên thuận tiện nhất trong ngôn ngữ lập trình bạn chọn)

tạo ra ít nhất một hình chữ nhật từ. Nếu không thể tạo hình chữ nhật từ với từ vựng và kích thước đã cho, chương trình không cần phải có hành vi xác định. Chương trình không cần thiết để có thể tạo các hình chữ nhật có chứa hơn 64 chữ cái hoặc có kích thước vượt quá 8 theo hai hướng. Chương trình sẽ có thể hoàn thành trong một khoảng thời gian hợp lý, giả sử, trong ba mươi phút hoặc ít hơn.


EDIT: Nếu bạn đang thực hiện một hình chữ nhật NxN, bạn được phép sử dụng một tệp từ điển nhỏ hơn chỉ chứa các từ có độ dài N chữ cái.


Tôi có thể điều chỉnh mã tôi đã viết cho trò chơi Java4k .
Peter Taylor

1
Tôi tò mò liệu có ai có triển khai có thể tạo ra một chiếc 8x8 từ danh sách từ đó trong vòng chưa đầy một giờ không.
MtnViewMark

@MtnViewMark Nếu không, tôi sẽ sẵn sàng hạ yêu cầu kích thước. Mặc dù vậy, tôi nghĩ rằng việc triển khai của Keith có thể được thực hiện nhanh hơn một chút nếu anh ta có thể thực hiện một số kiểm tra để giảm số lượng khả năng.
Peter Olson

và tất cả các từ phải khác nhau?
Ming-Tang

1
@MtnViewMark, thay vì chỉ kiểm tra xem tiền tố có khả thi hay không, tôi sử dụng bộ ba lưu trữ số lượng trẻ em dưới mỗi nút để đưa ra một heuristic mà phần tiếp theo có khả năng đưa ra giải pháp. (Sau đó tôi chọn một trọng số ngẫu nhiên theo heuristic - Tôi có lẽ nên thử chỉ chọn ứng cử viên tốt nhất, vì sự thay đổi kết quả không rõ ràng trong thông số kỹ thuật). Tôi đang thử nghiệm mức giảm để thiết lập trang bìa, giải quyết các liên kết nhảy múa của Knuth, trên cơ sở nó áp dụng phương pháp phỏng đoán trên toàn cầu thay vì tiền tố, nhưng cho đến nay không có triển vọng. Có lẽ có một sự giảm bớt tốt hơn.
Peter Taylor

Câu trả lời:


5

Haskell, 586 ký tự

import Data.List
import qualified Data.Vector as V
import System
data P=P[String](V.Vector P)
e=P[]$V.replicate 128 e
(a:z)∈(P w v)|a>' '=z∈(V.!)v(fromEnum a);_∈(P w _)=w
pw=q p w where q(P u v)=P(w:u).V.accum q v.x;x(a:z)=[(fromEnum a,z)];x _=[]
l%n=foldl'(∫)e.filter((==n).length)$l
d§(p,q:r)=map(\w->p++w:r)$q∈d;_§(p,_)=[p]
(d¶e)i=filter(not.any(null.(∈e))).map transpose.(d§).splitAt i
s i n d e m|i==n=["":m]|1<3=(d¶e)i m>>=(e¶d)i>>=s(i+1)n d e
p[b,a,n]w=take n$s 0(a`max`b)(w%a)(w%b)$replicate b$replicate a ' '
main=do{g<-map read`fmap`getArgs;interact$unlines.concat.p g.lines}

Được gọi bằng cách cung cấp 3 đối số: số lượng hàng, số cột, số lượng giải pháp; và danh sách từ được chấp nhận trên stdin:

$> ghc -O3 2554-WordRect.hs 
[1 of 1] Compiling Main             ( 2554-WordRect.hs, 2554-WordRect.o )
Linking 2554-WordRect ...

$> time ./2554-WordRect 7 7 1 < 2554-words.txt

zosters
overlet
seriema
trimmer
element
remends
startsy

real    0m22.381s
user    0m22.094s
sys     0m0.223s

Như bạn có thể thấy 7 × 7 chạy tương đối nhanh. Vẫn thời gian 8 × 8 và 7 × 6 ....

Nó sẽ ngắn hơn 9 ký tự để loại bỏ số lượng đối số giải pháp và chỉ tạo ra tất cả các giải pháp, nhưng sau đó nó trở nên không thể theo thời gian.


  • Chỉnh sửa: (585 → 455) thay thế cấu trúc dữ liệu tùy chỉnh bằng một bản đồ đơn giản của chuỗi tiền tố thành các thay thế có thể; Thật kỳ lạ, điều này chậm hơn một chút, có lẽ vì Map String achậm hơn một cây Map Char a...
  • Chỉnh sửa: (455 → 586) Lớn hơn?!? !! Phiên bản này tối ưu hóa không gian tìm kiếm hơn, sử dụng cả các kỹ thuật của giải pháp ban đầu của tôi và của các giải pháp python và awk. Hơn nữa, cấu trúc dữ liệu tùy chỉnh, dựa trên Vectornhanh hơn nhiều so với sử dụng đơn giản Map. Tại sao làm điều này? Bởi vì tôi nghĩ rằng một giải pháp gần với mục tiêu của 8x8 trong dưới giờ thì tốt hơn là một giải pháp ngắn hơn.

1
Phiên bản GHC nào bạn đang sử dụng? Sử dụng các lệnh tương tự (ngoại trừ tôi cần --makesau ghc) với danh sách từ được đăng trong câu hỏi, tôi nhận được các từ không có trong danh sách, như "zymesz" và "youthy".
Joey Adams

2
Có lẽ các yêu cầu nên được thay đổi để nói rằng lưới đầu ra không nên là chuyển vị của chính nó.
Peter Taylor

1
@Joey: Bạn đã chuyển đổi tập tin words.txt thành kết thúc dòng cục bộ chưa? Tôi đang chạy trên Mac OS X và tôi đã chuyển đổi tệp thành \ n kết thúc dòng trước khi sử dụng.
MtnViewMark

Cảm ơn, điều đó đã làm việc. Tệp đầu vào phải được viết thường có kết thúc dòng tương thích với hệ thống của một người.
Joey Adams

5

Python, 232 ký tự

x,y=input()
H=[]
P={}
for w in open('words.txt'):
 l=len(w)-2
 if l==x:H+=[w]
 if l==y:
  for i in range(y+1):P[w[:i]]=1
def B(s):
 if(x+2)*y-len(s):[B(s+w)for w in H if all((s+w)[i::x+2]in P for i in range(x))]
 else:print s
B('')

Nó chỉ có thể xử lý tối đa 6x6 trong giới hạn 1/2 giờ.


1
Nó chỉ tạo ra tất cả các cặp từ hoặc cặp từ hợp lệ? Khi tôi đọc dọc từ trên xuống dưới, nó dường như không tạo thành một từ hợp lệ. . Ví dụ, tôi có một kết quả "aahs", "tiếp tay", "thiếu", nhưng đọc theo chiều dọc "stk" không có trong danh sách từ, và cũng có thể cho ở trên tôi vượt qua tham số 3,3nhưng từ lợi nhuận của nó3x4
BẠN

Hmmm, đó không phải là những gì tôi nhận được. Tôi nghi ngờ vấn đề là với ngắt dòng trong từ điển. Tệp được cung cấp có dòng Windows (\ r \ n) trong đó, vì vậy độ dài của các từ là len (w) -2. Nếu bạn bằng cách nào đó đã chuyển đổi các ngắt dòng (hoặc nếu Python trên Windows thực hiện điều đó cho bạn?), Hãy đổi nó thành len (w) -1 và điều đó sẽ khắc phục nó.
Keith Randall

... và thay đổi +2s khác thành +1s.
Keith Randall

Ah tôi thấy. Tôi đã thử nghiệm với Windows và Linux. Python trên Windows tự động bị xóa \rkhỏi wvà trên Linux tôi đã chuyển đổi tệp sang định dạng Unix, vì vậy cả hai đều không hoạt động.
BẠN

Đây là một giải pháp rất thanh lịch.
asoundmove

3

Java (1065 byte)

import java.util.*;public class W{public static void main(String[]a){new
W(Integer.parseInt(a[0]),Integer.parseInt(a[1]));}W(int w,int h){M
H=new M(),V=new M();String L;int i,j,l,m,n=w*h,p[]=new int[n];long
I,J,K,M,C=31;long[]G=new long[h],T=new long[w],W[]=new long[n][],X;try{Scanner
S=new Scanner(new java.io.File("words.txt"));while(0<1){L=S.nextLine();l=L.length();for(i=0;i>>l<1;i++){K=0;for(j=0;j<l;j++)K+=(i>>j&1)*(L.charAt(j)-96L)<<5*j;if(l==w)H.put(K,H.g(K)+1);if(l==h)V.put(K,V.g(K)+1);}}}catch(Exception
E){}while(n-->0){j=1;if(W[n]==null){M=1L<<62;for(i=w*h;i-->0;){m=i/w;l=i%w*5;if((G[m]>>l&C)<1){X=new
long[27];I=K=0;for(;K++<26;){J=H.g(G[m]+(K<<l))*V.g(T[i%w]+(K<<5*m));X[(int)K]=K-32*J;I+=J;}if(I<1)j=0;if(I<M){M=I;p[n]=i;W[n]=X;}}}}X=W[n];Arrays.sort(X);M=X[0]*j;X[0]=0;K=M&C;i=p[n]%w;j=p[n]/w;l=5*i;m=5*j;G[j]&=~(C<<l);G[j]+=K<<l;T[i]&=~(C<<m);T[i]+=K<<m;if(M>=0){W[n]=null;n+=2;}}for(long
A:G){L="";for(i=0;i<w;)L+=(char)(96+(C&A>>5*i++));System.out.println(L);}}class
M extends HashMap<Long,Long>{long g(Long s){return get(s)!=null?get(s):0;}}}

Một chặng đường dài từ ngắn nhất, nhưng tôi nghĩ đó là cách gần nhất để đáp ứng các hạn chế về thời gian. Tôi đã lưu 14 byte bằng cách giả sử rằng tệp đầu vào đã được lọc thành các từ có độ dài phù hợp; trên netbook của tôi, nếu bạn cung cấp toàn bộ words.txtthì nó dành thời gian tiền xử lý phút đầu tiên, loại bỏ hầu hết những gì nó tạo ra và sau đó chỉ mất 20 giây để giải quyết 7x7. Trên máy tính để bàn của tôi, nó thực hiện toàn bộ trong vòng dưới 15 giây, cho:

rascals
areolae
serrate
coroner
alanine
latents
seeress

Tôi đã để nó chạy trong hơn 50 giờ mà không tìm thấy giải pháp cho 8x7 hoặc 8x8. Các từ 8 chữ cái dường như là một ranh giới quan trọng cho vấn đề này - nó chỉ xoay quanh một nửa mà không có nhiều tiến bộ.

Cách tiếp cận được sử dụng là xoay vòng hoàn toàn và theo kinh nghiệm dựa trên số lần hoàn thành theo chiều ngang có thể nhân với số lần hoàn thành theo chiều dọc có thể. Ví dụ: nếu chúng ta có lưới trung gian

*ean*
algae
*ar**
*ier*
*nee*

sau đó chúng tôi cung cấp cho góc trên bên trái một giá trị heuristic của count(aean*)count(aa***) + count(bean*)count(ba***) + ... + count(zean*)count(za***). Trong tất cả các ô chúng tôi chọn một ô có giá trị heuristic nhỏ nhất (nghĩa là khó thỏa mãn nhất), và sau đó hoạt động mặc dù các chữ cái theo thứ tự giảm dần của số tiền chúng đã đóng góp vào giá trị heuristic của ô đó (nghĩa là bắt đầu bằng khả năng thành công nhất ).


Cách tiếp cận và giải thích đáng yêu.
MtnViewMark

2

F #

Giải pháp quay lui, nhưng tôi sẽ tối ưu hóa không gian tìm kiếm sau này.

open System

(*-NOTES
    W=7 H=3
    abcdefg<-- searching from wordsW
    abcdefg
    abcdefg
    ^
    partial filtering from wordsH
  *)

let prefix (s : char[]) (a : char[]) =
  a.[0..s.Length - 1] = s

let filterPrefix (s : char[]) =
  Array.filter (prefix s)

let transpose (s : char[][]) =
  [|
    for y = 0 to s.[0].Length - 1 do
      yield [|
        for x = 0 to s.Length - 1 do
          yield s.[x].[y]
      |]
  |]

[<EntryPoint>]
let main (args : String[]) =
  let filename, width, height = "C:\Users\AAA\Desktop\words.txt", 3, 3
  let lines = System.IO.File.ReadAllLines filename |> Array.map (fun x -> x.ToCharArray())
  let wordsW = Array.filter (Array.length >> ((=) width)) lines
  let wordsH = Array.filter (Array.length >> ((=) height)) lines

  let isValid (partial : char[][]) =
    if partial.Length = 0 then
      true
    else
      seq {
        for part in transpose partial do
          yield Seq.exists (prefix part) wordsH
      }
      |> Seq.reduce (&&)

  let slns = ref []
  let rec back (sub : char[][]) =
    if isValid sub then
      if sub.Length = height then
        slns := sub :: !slns
      else
        for word in wordsW do
          back <| Array.append sub [| word |]

  back [| |]
  printfn "%A" !slns
  0

1

ôi, 283

(có thể cần thêm 14 cho các cờ đầu vào tham số)

Gọi với ví dụ awk -v x=2 -v y=2...
Tìm trận đấu đầu tiên và in nó (283 ký tự):

{if(x==L=length)w[++n]=$0;if(y==L)for(;L>0;L--)W[substr($0,1,L)]++}END{for(i[Y=1]++;i[j=1]<=n;){b[Y]=w[i[Y]];while(j<=x){s="";for(k=1;k<=Y;k++)s=s substr(b[k],j,1);W[s]?0:j=x;j++}if(W[s])if(Y-y)i[++Y]=0;else{for(k=1;k<=Y;k++)print b[k];exit}i[Y]++;while(Y>1&&i[Y]>n)i[--Y]++}print N}

Tìm số lượng trận đấu (245 ký tự, chậm hơn nhiều):

{if(x==L=length)w[++n]=$0;if(y==L)for(;L>0;L--)W[substr($0,1,L)]++}END{for(i[Y=1]++;i[j=1]<=n;){b[Y]=w[i[Y]];while(j<=x){s="";for(k=1;k<=Y;k++)s=s substr(b[k],j,1);W[s]?0:j=x;j++}W[s]?Y-y?i[++Y]=0:N++:0;i[Y]++;while(Y>1&&i[Y]>n)i[--Y]++}print N}

Đối với cả hai chương trình (tất nhiên là nhiều hơn cho số lượng giải pháp), thời gian chạy vượt quá 30 phút đối với một số giá trị của x và y.

Cũng giống như một vấn đề quan tâm, đây là số từ cho mỗi độ dài từ:

 2     85
 3    908
 4   3686
 5   8258
 6  14374
 7  21727
 8  26447
 9  16658
10   9199
11   5296
12   3166
13   1960
14   1023
15    557
16    261
17    132
18     48
19     16
20      5
21      3
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.