danh sách dài nhất các từ có chữ cái bắt đầu và kết thúc


11

Bạn tôi đã cho tôi một vấn đề mà anh ta nói là dễ, nhưng tôi không thể tìm ra một thuật toán tốt để sử dụng để làm điều đó.

Bạn được cung cấp một đầu vào của 100 từ tiếng Anh ngẫu nhiên. Bạn phải tìm chuỗi từ dài nhất trong đó chữ cái cuối cùng trong một từ khớp với chữ cái đầu tiên trong từ tiếp theo. Bạn chỉ có thể sử dụng mỗi từ một lần.

Ví dụ: nếu bạn được cho các từ "cat", "dog", "that", chuỗi dài nhất bạn có thể thực hiện sẽ là "cat -> that". Nếu bạn được cho các từ "chuột", "nai", "kỳ lân", chuỗi dài nhất bạn có thể tạo sẽ chỉ là một từ (vì không có từ nào trong số đó liên kết). Nếu bạn được cho các từ "chim", "món ăn", "harb", chuỗi dài nhất bạn có thể làm là "harb -> bird -> món ăn" (hoặc "món ăn -> harb -> chim" hoặc "chim - > món ăn -> harb ").

Tôi đã nảy ra ý tưởng mô hình hóa nó như một biểu đồ tuần hoàn có hướng. Mỗi nút sẽ chỉ là một từ, với các đỉnh sẽ đến từng từ / nút bắt đầu bằng chữ cái mà từ này kết thúc bằng.

+-------+         \ +------+
|  cat  |-----------| that |
+-------+         / +------+
    |                  |
   \|/                 |
+-------+ /            |
|  the  |--------------+
+-------+ \

Vấn đề này dường như là một tìm kiếm đường dẫn dài nhất , đó là NP-Hard.

Có cách nào tốt hơn để làm điều đó? Hoặc thậm chí một số loại thuật toán gần đúng có thể được sử dụng? Hoặc một số cách để khai thác chất lượng tiếng Anh để giảm không gian tìm kiếm?


4
Với 100 từ, bạn nhận được (ít nhất) 100! = 9.332622e + 157 kết hợp. Chúc may mắn với điều đó, tôi nghĩ rằng bạn của bạn đang kéo chân bạn nói rằng điều này là dễ dàng.
Martin Wickman

1
Nhưng, số lượng kết hợp có thể ít hơn nhiều, vì trung bình một từ duy nhất chỉ được liên kết với khoảng 6 hoặc 7 từ khác.
Công cụ Abe

2
Bạn đúng rằng đây chính xác là một tìm kiếm đường dẫn dài nhất. Tôi nghĩ bạn của bạn sai. Tuy nhiên, một tìm kiếm toàn diện không khó để viết mã và có thể không chạy lâu như vậy.
kevin cline

4
Để giải trí, tôi đã mã hóa một tìm kiếm toàn diện về sức mạnh vũ phu (như @kevincline đã chỉ ra) trong Ruby ( gist.github.com/anonymous/6225361 ). Với 100 từ, chỉ mất ~ 96 giây ( gist.github.com/anonymous/6225364 ). Và đây là một kịch bản không hiệu quả cao, không được tối ưu hóa, ngôn ngữ diễn giải, nhanh và bẩn. Vì vậy, chỉ với 100 từ, ngay cả một phiên bản chậm của lực lượng vũ phu chạy trong một khoảng thời gian lành mạnh. Mã của tôi không thực sự tạo ra một biểu đồ tuần hoàn và sau đó tìm kiếm thông qua nó, nó chỉ xây dựng đệ quy mọi đường dẫn có thể bắt đầu từ mỗi từ và theo dõi những từ dài nhất.
Ben Lee

3
Vấn đề nói rằng có 100 từ. Tôi nghĩ điều này có nghĩa là bạn có thể áp dụng một giải pháp lập trình động, được đề cập trong bài viết mà bạn đang đề cập.
Julien Guertault

Câu trả lời:


5

Tôi nghĩ rằng điều này có liên quan đến vấn đề con đường dài nhất (LP) mà bạn đã đề cập, nhưng nó hơi khác một chút. Sự khác biệt chính là vấn đề LP có mức độ kết nối cao hơn so với vấn đề được đề xuất của bạn. Bằng cách giới hạn các kết nối của bạn đến các chữ cái cuối cùng và đầu tiên, bạn loại bỏ một số lượng lớn các kết hợp tiềm năng.

Đây là cách tôi khuyên bạn nên giải quyết vấn đề này:

  1. Đối với mỗi từ trong danh sách, hãy đếm các kết nối có thể có và kết nối ra.
  2. Hủy bỏ bất kỳ từ nào có 0 in và 0 outs.
  3. Xác định một tập hợp "từ bắt đầu" ban đầu với số lần nhập và xuất thấp nhất và số lần xuất phát phải lớn hơn 0.
  4. Mỗi từ bắt đầu nhận bản sao làm việc riêng của nó về số lượng kết nối vào / ra. Điều này tạo thành người đứng đầu của chuỗi.
  5. Đối với mỗi chuỗi, xác định danh sách "các từ tiếp theo" dựa trên:
    • chữ cái cuối của từ bắt đầu hoặc từ trước
    • số lượng kết nối trong và ngoài thấp nhất (một lần nữa, số lần kết nối phải lớn hơn 0)
  6. Đối với mỗi next word, lặp lại bước 5 cho đến khi chuỗi kết thúc.

Hãy ghi nhớ rằng:

  • Bạn sẽ cần theo dõi độ dài của chuỗi và có một số cơ chế toàn cầu để xác định chuỗi dài nhất.

  • Bạn cũng cần xóa từng từ khỏi bản sao làm việc của số lượng kết nối để tránh vòng lặp đệ quy.

  • Tại một số điểm, chuỗi của bạn sẽ chấm dứt và bạn phải chọn một từ có số lượng kết nối 0.

  • Bạn có thể phải tính toán lại / in vì các từ bị xóa khỏi danh sách làm việc. Thoạt nhìn, tôi không nghĩ rằng điều này sẽ cần thiết vì các bộ tổng thể sẽ tương đối nhỏ. Nếu bạn thu nhỏ tới 1000 từ, thì việc đếm số tĩnh có thể làm chậm thuật toán hội tụ.

Tôi thấy đây là một vấn đề đóng gói. Đối với tôi, các kết nối trong và ngoài xác định hình dạng sẽ được đóng gói. Các kết nối càng thấp, hình dạng càng kỳ lạ. Hình dạng càng kỳ lạ, tôi càng muốn gói nó càng sớm vì tôi nhận thấy việc giảm tỷ lệ có thể đóng gói một hình dạng kỳ lạ sau khi tôi vào chuỗi.

Ví dụ:

{dog, gopher, alpha, cube, elegant, this, that, bart}

dog     0, 1
gopher  1, 0
alpha   0, 0
cube    0, 1
elegant 1, 2
this    3, 0
that    2, 1
bart    0, 2

//alpha is dropped with 0 in and 0 out.
//two candidates found: dog, cube

//chain 1
dog => gopher
//chain 2
cube => elegant => that => this

//Note 1: the following chain won't occur due to selection rules
//that takes priority over this because of output count
cube => elegant => this

//Note 2: this chain won't occur either due to selection rules
bart => that => this

2
Có đảm bảo rằng thuật toán này sẽ luôn tìm thấy con đường dài nhất? Ngoài đỉnh đầu, tôi không thể nghĩ ra một ví dụ ngược lại, nhưng điều này có vẻ như nó có thể thuộc về một giải pháp loại "tối đa cục bộ".
Ben Lee

@BenLee - Tôi là kỹ sư phần mềm; Tôi không bao giờ đảm bảo mã của tôi. :-) Nghiêm túc mà nói, tôi không biết câu trả lời cho câu hỏi của bạn. Lý thuyết tập hợp và kỹ năng chứng minh toán học của tôi rất yếu, để nói một cách nhẹ nhàng, vì vậy tôi không có cách nào ngoài việc đánh giá theo kinh nghiệm để xác nhận thuật toán của tôi. Tôi không chắc vấn đề này thực sự khó NP, nhưng tôi cũng không thể xác nhận yêu cầu đó. Nếu đó không phải là NP-hard thì phải có một phương tiện để xác nhận thuật toán.

2
Điều gì về một danh sách từ như thế này: "dog, gopher, bun, nun, noon, nub". Thuật toán sẽ chọn không chính xác danh sách dài nhất là "dog -> gopher", khi nó thực sự là bất kỳ sự kết hợp nào của "bun, nun, noon, nub".
Công cụ Abe

1
@AbeTool - ví dụ hay đấy. Tôi sẽ thêm một lần lặp (hoặc hai) khác để cho phép kết hợp "đầu vào thấp nhất> = 1" và "đầu ra thấp nhất> = 1" sau đó.

2
Tôi không nghĩ rằng điều đó sẽ giải quyết vấn đề trong mọi trường hợp. Tôi nghĩ rằng điều này rơi vào một giải pháp loại "tối đa địa phương".
Công cụ Abe

3

Nếu bạn tạo ma trận 26X26 để biểu thị đồ thị có hướng của đỉnh như mỗi bảng chữ cái và các từ làm cạnh. Ví dụ từ - APPLE kết nối đỉnh A và E với cạnh được hướng từ A đến E. Bây giờ, vấn đề giảm xuống để tìm đường Euler lớn nhất (đường dẫn bao gồm số cạnh tối đa, truy cập mỗi cạnh một lần có thể lặp lại các đỉnh) trong biểu đồ. Một trong những thuật toán O (E) sẽ là bắt đầu ngẫu nhiên từ một cặp đỉnh. Tìm một con đường giữa chúng. Hơn tiếp tục thư giãn con đường cho đến khi nó có thể.

update @ GlenH7 Tôi đã giải quyết một câu hỏi tương tự trên www.hackerearth / jda gần đây, có những điểm tương đối liên quan đến giải pháp tốt nhất và tôi đã đạt điểm cao nhất với sự chấp thuận sau đây-

Đưa ra danh sách các từ. Tìm chuỗi dài nhất có thể được hình thành bởi chúng. Chuỗi có giá trị nếu mỗi từ bắt đầu bằng một chữ cái * kết thúc ở cuối từ cuối cùng.

Ứng dụng =

1) tạo đồ thị của bảng chữ cái dưới dạng các đỉnh và các từ làm các cạnh. Thay vì sử dụng nhiều cạnh, hãy sử dụng một cạnh có trọng số bằng số cạnh.

2) tìm thành phần kết nối mạnh của đồ thị với các cạnh tối đa. Tạm thời loại bỏ các cạnh khác.

3) Với mỗi đỉnh làm cho độ chính xác của nó bằng với độ lệch của nó.

4) Bây giờ mạch eulerian tồn tại của họ trong đồ thị. Tìm nó.

5) Bây giờ trong biểu đồ còn lại (biểu đồ wrt orignal tìm đường dài nhất với đỉnh đầu tiên trong thành phần được kết nối mạnh được chọn. Tôi nghĩ rằng đây là NP cứng.

6) Bao gồm đường mòn trên trong mạch Elerian chuyển đổi mạch điện tử thành đường mòn.

Tại sao - Tôi chấp nhận rằng câu hỏi này rất có thể là NP khó (đoán, không nói theo toán học). Nhưng cách tiếp cận trên hoạt động tốt nhất khi có một danh sách dài (1000+) từ được phân phối đồng đều (nghĩa là không có ý định trở thành wc cho cách tiếp cận trên). Chúng ta hãy giả sử rằng sau khi chuyển đổi danh sách đã cho thành biểu đồ được đề cập ở trên, may mắn thay, đó là một biểu đồ eulerian (xem http://en.wikipedia.org/wiki/Eulerian_path để biết điều kiện), sau đó không nghi ngờ gì chúng ta có thể nói câu trả lời đó với câu hỏi trên là P và thực sự là đường dẫn eulerian trong biểu đồ (xem http://www.graph-magics.com/articles/euler.php để biết cách đơn giản để làm như vậy và xem điều này để xác minh rằng biểu đồ của bạn có đơn http://www.geekforgeek.org/strongly-connected-components/và nếu không tạm thời làm sạch scc nhỏ khác vì đường dẫn euler tồn tại cho scc đơn). Vì vậy, đối với các trường hợp không may mắn (gần như tất cả các trường hợp) tôi cố gắng chuyển đổi chúng thành các trường hợp may mắn (tức là điều kiện đường mòn eulerian được đáp ứng). làm như thế nào? Tôi đã cố gắng tăng cường tìm kiếm độ sâu cho các cạnh không liên quan (tập hợp các cạnh trong một đường dẫn nhìn từ đỉnh có độ lệch lớn hơn độ lớn và kết thúc ở đỉnh có độ lớn hơn độ lệch). Tăng tìm kiếm theo chiều sâu có nghĩa là trước tiên tôi đã tìm kiếm tất cả các cạnh của một cạnh trong đường dẫn hơn hai cạnh trong đường dẫn, v.v. Thoạt nhìn có vẻ như tìm kiếm theo chiều sâu sẽ mất O (các nút ^ i) do đó tổng độ phức tạp thời gian của O (các nút + nút ^ 2 + nút ^ 3 + ....) cho đến khi đó là một trường hợp may mắn. Nhưng phân tích khấu hao sẽ tiết lộ nó là O (các cạnh). Một khi nó được giảm trường hợp may mắn tìm mạch eulerian.

Cho đến đây là tất cả thời gian đa thức. Điều này sẽ cung cấp gần như giải pháp tốt nhất. Nhưng để tăng thêm giải pháp của bạn (giải pháp hoàn hảo là NP khó) hãy thử một số cách tiếp cận tham lam trong biểu đồ còn lại để tìm một vệt dài nhìn chằm chằm với một trong các đỉnh trong scc đã chọn. Bây giờ thêm điều này vào đường mòn eulerian tìm thấy ở trên để tăng thêm nó.


@ GlenH7 Tôi đã giải quyết một câu hỏi tương tự trên www.hackerearth / jda gần đây, có những điểm tương đối liên quan đến giải pháp tốt nhất và tôi đã đạt điểm cao nhất với sự chấp thuận sau
vishfrnds

0

Ý tưởng:

Đầu tiên, tạo hai bản đồ (băm), nói, S và E, từ các chữ cái trong bảng chữ cái đến các từ; đầu tiên, S, ánh xạ các chữ cái bắt đầu thành các từ, thứ hai, E, tương tự với các chữ cái kết thúc.

Ví dụ: nếu từ điển được làm bằng:

chim, món ăn, chó, harb

chúng ta có:

S:

a -> [ ]
b -> [ bird ]
c -> [ ]
d -> [ dish, dog ]
...
h -> [ harb ]
...

và,

E:

a -> [ ]
b -> [ harb ]
c -> [ ]
d -> [ bird ]
...
g -> [ dog ]
h -> [ dish ]
...

Tiếp theo, sử dụng S và E để tra cứu nhanh, tạo một khu rừng (bộ cây), có cùng kích thước với từ điển, với các gốc ở mỗi từ và không cho phép một từ xuất hiện nhiều hơn một lần trong cây - lưu trữ bộ đệm độ sâu của cây khi bạn xây dựng chúng:

bird (depth: 2)
   dish
      harb
   dog

dish (depth: 3)
   harb
      bird
         dog

dog (depth: 0)

harb (depth: 2)
   bird
      dish
      dog

Cuối cùng, lặp đi lặp lại trong rừng và tìm (các) cây có độ sâu lớn nhất.

(Các) giải pháp sẽ nằm trên trục con cháu của những cây đó.

Ví dụ,

dish / harb / bird / dog

ở trên.

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.