2011-10-13 15 views
11

Sau một vài đêm bận rộn, đầu của tôi không hoạt động tốt, nhưng điều này cần được khắc phục ngày hôm qua, vì vậy tôi hỏi cộng đồng SO được làm mới hơn.Cần một thuật toán để tách một chuỗi số

Tôi có một chuỗi số. Ví dụ:

1, 5, 7, 13, 3, 3, 4, 1, 8, 6, 6, 6

tôi cần phải chia loạt bài này thành ba phần để tổng các con số trong tất cả các bộ phận càng gần càng tốt. Thứ tự của các số cần phải được duy trì, vì vậy phần đầu tiên phải bao gồm các số X đầu tiên, số thứ hai - của các số Y tiếp theo và thứ ba - của bất kỳ số nào còn lại.

Thuật toán để làm điều này là gì?

(Lưu ý: vấn đề thực tế là sắp xếp các đoạn văn bản có chiều cao khác nhau thành ba cột. Đoạn văn phải duy trì trật tự (dĩ nhiên) và chúng không thể chia làm hai phần.)

+0

Câu hỏi trùng lặp? http://stackoverflow.com/questions/3009146/splitting-values-into-groups-evenly – kan

+0

Đóng, nhưng điều đó cho phép sắp xếp lại các giá trị. Tôi nghĩ rằng trường hợp của tôi nên đơn giản hơn, nhưng thuật toán được đề cập ở đây không hữu ích ở đây. –

+1

Ba phần - đây có phải là yêu cầu hay chỉ là một ví dụ? –

Trả lời

6

tiên, chúng ta sẽ cần phải xác định mục tiêu thì càng tốt:

Giả sử số tiền một phần là A1, A2, A3, Chúng tôi đang cố gắng để giảm thiểu | A-A1 | + | A-A2 | + | A-A3 |. A là giá trị trung bình: A = (A1 + A2 + A3)/3.

Vì vậy, chúng tôi đang cố gắng giảm thiểu | A2 + A3-2A1 | + | A1 + A3-2A2 | + | A1 + A2-2A3 |.

Cho S biểu thị tổng (hằng số): S = A1 + A2 + A3, vì vậy A3 = S-A1-A2.

Chúng tôi đang cố gắng để giảm thiểu:

| A2 + S-A1-A2-2A1 | + | A1 + S-A1-A2-2A2 | + | A1 + A2-2S + 2A1 + 2a2 | = | S-3A1 | + | S-3A2 | + | 3A1 + SA2-2S |

biểu thị chức năng này như f, chúng tôi có thể làm hai vòng O (n^2) và theo dõi tối thiểu:

Cái gì như:

for (x=1; x<items; x++) 
{ 
    A1= sum(Item[0]..Item[x-1]) 
    for (y=x; y<items; y++) 
    { 
     A2= sum(Item[x]..Item[y-1]) 
     calc f, if new minimum found -keep x,y 
    } 
} 
+0

Vâng, điều này rất đơn giản. Và tôi thấy cách điều này có thể được điều chỉnh theo một "hàm chi phí" khác, tương tự như thuật toán của Knuth. Không hiệu quả, nhưng cải tiến có thể được thực hiện. Mặt khác - tôi sẽ hiếm khi (nếu có) nhận được hơn 20 nhóm, vì vậy có lẽ đây thậm chí là tốt nhất về khả năng bảo trì. –

+0

trên algo thực sự là [brute force algo] O (n^3), n^2 cho hai vòng và n để tổng kết trong vòng lặp bên trong. – vikas368

+0

@ vikas368: Thực tế là không. Bạn chỉ cần thêm một mục duy nhất trong mỗi lần lặp lại. Tôi đã viết nó theo cách này chỉ để làm sáng tỏ. –

3

Tôi tin rằng điều này có thể được giải quyết với a dynamic programming algorithm for line breaking được phát minh bởi Donald Knuth để sử dụng trong TeX.

+1

Thú vị, nhưng thuật toán đó dựa trên kích thước đường tối đa đã biết. Các cột của tôi không có giới hạn - chúng chỉ cần ở gần nhau nhất có thể, để cho kết quả về mặt thẩm mỹ. –

+0

Tôi nghĩ rằng thuật toán là để phá vỡ một chuỗi các số thành bất kỳ số lượng phân đoạn nào, mỗi số có tổng số là một số k nhất định và có kích thước tương tự với nhau càng tốt. Những gì chúng tôi muốn ở đây là để phá vỡ trình tự thành một số cố định của các phân đoạn (3) có kích thước tương tự với nhau càng tốt, đó là hơi khác nhau. Nhưng nó vẫn có thể hữu ích để thử thiết lập k = sum/3 hoặc thereabouts. –

4

tìm tổng sốtổng tích lũy của chuỗi.

được a = sum/3

sau đó xác định vị trí gần một, 2 * a trong tổng tích lũy mà chia danh sách của bạn thành ba phần bằng nhau.

2

Theo câu trả lời của Aasmund Eldhuset, trước đây tôi đã trả lời câu hỏi này về SO.

Word wrap to X lines instead of maximum width (Least raggedness)

algo này không dựa vào kích thước dòng tối đa nhưng chỉ đưa ra một cắt tối ưu.

tôi sửa đổi nó để làm việc với vấn đề của bạn:

L=[1,5,7,13,3,3,4,1,8,6,6,6] 

def minragged(words, n=3): 


P=2 
cumwordwidth = [0] 
# cumwordwidth[-1] is the last element 
for word in words: 
    cumwordwidth.append(cumwordwidth[-1] + word) 
totalwidth = cumwordwidth[-1] + len(words) - 1 # len(words) - 1 spaces 
linewidth = float(totalwidth - (n - 1))/float(n) # n - 1 line breaks 

print "number of words:", len(words) 
def cost(i, j): 
    """ 
    cost of a line words[i], ..., words[j - 1] (words[i:j]) 
    """ 
    actuallinewidth = max(j - i - 1, 0) + (cumwordwidth[j] - cumwordwidth[i]) 
    return (linewidth - float(actuallinewidth)) ** P 

""" 
printing the reasoning and reversing the return list 
""" 
F={} # Total cost function 

for stage in range(n): 
    print "------------------------------------" 
    print "stage :",stage 
    print "------------------------------------" 
    print "word i to j in line",stage,"\t\tTotalCost (f(j))" 
    print "------------------------------------" 


    if stage==0: 
     F[stage]=[] 
     i=0 
     for j in range(i,len(words)+1): 
      print "i=",i,"j=",j,"\t\t\t",cost(i,j) 
      F[stage].append([cost(i,j),0]) 
    elif stage==(n-1): 
     F[stage]=[[float('inf'),0] for i in range(len(words)+1)] 
     for i in range(len(words)+1): 
       j=len(words) 
       if F[stage-1][i][0]+cost(i,j)<F[stage][j][0]: #calculating min cost (cf f formula) 
        F[stage][j][0]=F[stage-1][i][0]+cost(i,j) 
        F[stage][j][1]=i 
        print "i=",i,"j=",j,"\t\t\t",F[stage][j][0]    
    else: 
     F[stage]=[[float('inf'),0] for i in range(len(words)+1)] 
     for i in range(len(words)+1): 
      for j in range(i,len(words)+1): 
       if F[stage-1][i][0]+cost(i,j)<F[stage][j][0]: 
        F[stage][j][0]=F[stage-1][i][0]+cost(i,j) 
        F[stage][j][1]=i 
        print "i=",i,"j=",j,"\t\t\t",F[stage][j][0] 

print 'reversing list' 
print "------------------------------------" 
listWords=[] 
a=len(words) 
for k in xrange(n-1,0,-1):#reverse loop from n-1 to 1 
    listWords.append(words[F[k][a][1]:a]) 
    a=F[k][a][1] 
listWords.append(words[0:a]) 
listWords.reverse() 

for line in listWords: 
    print line, '\t\t',sum(line) 

return listWords 

kết quả tôi nhận được là:

[1, 5, 7, 13]  26 
[3, 3, 4, 1, 8]   19 
[6, 6, 6]  18 
[[1, 5, 7, 13], [3, 3, 4, 1, 8], [6, 6, 6]] 

Hy vọng nó giúp

+0

Uff, python. Không phải một trong những ngôn ngữ tôi rất quen thuộc. Sẽ mất một lúc để gặm nhấm. Tôi bị cám dỗ để bắt đầu với giải pháp của Lior Kogan, ném vào một chức năng chi phí khác và một vài tối ưu hóa để giảm số vòng lặp. Vì loạt bài của tôi thường sẽ ngắn (20 bài là một phần lớn), một thuật toán bậc hai không phải là tất cả những điều xấu. Nhưng trong thời gian có nghĩa là - có một upvote! :) –

+0

@ Vilx- Tôi đã cố gắng viết một bản ngã theo từng bước chương trình động cho sự rách rưới nhất, vì vậy nó không phải là rất khó hiểu. Nhưng bạn có thể tìm thấy rất nhiều phiên bản (đặc biệt là một trong C#) của mã này trong liên kết tôi đăng trên đầu câu trả lời của tôi ,. –

+0

Cảm ơn bạn. C# là điều của tôi thực sự. :) –

3

phép nói rằng p là mảng của bạn độ cao đoạn;

int len= p.sum()/3; //it is avarage value 
int currlen=0; 
int templen=0; 
int indexes[2]; 
int j = 0; 
for (i=0;i<p.lenght;i++) 
{ 
    currlen = currlen + p[i]; 
    if (currlen>len) 
    { 
     if ((currlen-len)<(abs((currlen-p[i])-len)) 
     { //check which one is closer to avarege val 
      indexes[j++] = i; 
      len=(p.sum()-currlen)/2   //optional: count new avearege height from remaining lengths 
      currlen = 0; 
     } 
     else 
     { 
      indexes[j++] = i-1; 
      len=(p.sum()-currlen)/2 
      currlen = p[i]; 
     } 
    } 
    if (j>2) 
     break; 
} 

Bạn sẽ nhận được chỉ mục bắt đầu của chuỗi thứ 2 và thứ 3. Lưu ý loại hình này của mã giả :)

+0

Vẫn xứng đáng được định dạng. OK, tôi có ý tưởng. –