2013-05-16 61 views
10

Tôi có vấn đề cần giải quyết. N số tự nhiên được đưa ra. Tôi cần phải tìm một danh sách các số tự nhiên mà tổng lên đến con số nhất định và đồng thời các phần tử nghịch đảo lên đến 1.Tất cả các số tự nhiên tổng hợp thành N và tổng số nghịch đảo tổng hợp lên một

a + b + c + ... = N 
1/a + 1/b + 1/c + ... = 1 

a, b, c không phải là duy nhất.

Tôi đã đưa ra mã sau trong Java. Nó hoạt động cho các trường hợp đơn giản, nhưng cực kỳ chậm đối với N > 1000.

Tôi có thể viết lại phương thức sao cho nó hoạt động nhanh ngay cả đối với hàng triệu? Có lẽ, tôi nên thả ra đệ quy hoặc cắt đứt một số chi nhánh với lừa toán học mà tôi bỏ lỡ?

SSCEE:

private final static double ONE = 1.00000001; 

public List<Integer> search (int number) { 
    int bound = (int)Math.sqrt(number) + 1; 
    List<Integer> list = new ArrayList<Integer>(bound); 

    if (number == 1) { 
     list.add(1); 
     return list; 
    } 

    for (int i = 2; i <= bound; i++) { 
     list.clear(); 
     if (simulate(number, i, list, 0.0)) break; 
    } 

    return list; 
} 


//TODO: how to reuse already calculated results? 
private boolean search (int number, int n, List<Integer> list, double sum) { 
    if (sum > ONE) { 
     return false; 
    } 

    //would be larger anyway 
    double minSum = sum + 1.0/number; 
    if (minSum > ONE) { 
     return false; 
    } 

    if (n == 1) { 
     if (minSum < 0.99999999) { 
      return false; 
     } 

     list.add(number); 
     return true; 
    } 

    boolean success = false; 
    for (int i = 2; i < number; i++) { 
     if (number - i > 0) { 
      double tmpSum = sum + 1.0/i; 
      if (tmpSum > ONE) continue; 

      list.add(i); 
      success = search(number - i, n - 1, list, tmpSum); 
      if (!success) { 
       list.remove(list.size() - 1); 
      } 

      if (success) break; 
     } 
    } 

    return success; 
} 
+1

Tôi nghĩ '1/a + 1/b + 1/c + ... = N' là lỗi đánh máy, phải là' = 1', phải không? –

+0

Chỉ cần làm rõ, {a, b, ...} phải là số nguyên, phải không? Ngoài ra, bạn có cho phép cả số dương và số âm? – adrianp

+0

Nên a, b, c, ... de dinstinct? – Thomash

Trả lời

11

Giấy "A Theorem on Partitions", 1963 by Graham, R. L. cho thấy rằng đối với N> 77, có một giải pháp mà các số được sử dụng là kiến ​​thức và đề xuất một thuật toán để tìm phân tích như vậy.

Thuật toán như sau:

  • Nếu N là ít hơn 333, sử dụng một bảng precomputed để lấy kết quả.
  • Nếu N là số lẻ, hãy tìm một phân hủy d1, d2, d3, d4, ..., dk cho (N-179)/2, sau đó 3, 7, 78, 91, 2*d1, 2*d2, 2*d3, ..., 2*dk là một phân hủy cho N
  • Nếu N là chẵn, tìm một phân hủy d1, d2, d3, d4, ..., dk cho (N-2)/2, sau đó 2, 2*d1, 2*d2, 2*d3, ..., 2*dk là một phân hủy cho N

Nhưng vì bạn không quan tâm đến việc có số riêng biệt trong phân tách, bạn có thể giảm kích thước của bảng cho kết quả được tính trước thành 60 và trong trường hợp N là số lẻ, hãy tìm cách phân tích d1, d2, d3, d4, ..., dk cho (N-9)/2, sau đó 3, 6, 2*d1, 2*d2, 2*d3, ..., 2*dk là phân hủy cho N.

+0

'(N-179)/2' đó là điên rồ! –

+0

Vì bạn không quan tâm đến các số dincstinct, bạn không cần 179 này, tôi đã cập nhật câu trả lời. – Thomash

+0

trong đó '60' và' (N-9)/2' xuất phát từ đâu? –

-2

Nếu những con số không phải là số nguyên a = b = c = ... = sqrt(N) là một giải pháp.

Nếu số âm được cho phép, sau đó tìm ab8a+3b+1=N (bạn có thể tính toán chúng với Euclide's algorithm) và sau đó danh sách bạn muốn là: số 3 (lần 3a), số 2 (2b lần) và số 1 (1-ab lần)

+0

chúng phải là số nguyên. tiêu cực không được phép. –

+0

không phải là một downvoter –

0

Đầu tiên, hãy thay đổi điều kiện thứ hai để bạn không phải thực hiện bất kỳ dấu phẩy động nào. Thay đổi (1/a + 1/b + 1/c) = 1 đến bc + ac + ab = abc. Bạn có thể tính toán điều này với các đơn vị O (k) (Gợi ý: Tính toán phía bên phải trước).

Thứ hai, hợp nhất số của bạn. Ví dụ: nếu bạn có a, b, c, a, b làm đầu vào, hãy hợp nhất các số nhị phân và lưu nó thành hai, hai b và một c.

Thứ ba, có giải pháp dựa trên DP để giải quyết vấn đề đầu tiên một cách hiệu quả. Bạn sẽ phải lưu trữ tất cả các câu trả lời một phần là tốt. Tuy nhiên bạn có thể lưu trữ một phần câu trả lời khá hiệu quả. Ví dụ. Lưu trữ "x = bc + ac + ab" và "y = abc" làm giải pháp từng phần. Khi bạn thêm d vào hỗn hợp, bạn có xnew = x * d + y và ynew = y * d.

Nếu bạn sử dụng ba con trỏ này, giải pháp của bạn có thể hiệu quả hơn.

Các vấn đề liên quan