Lập chỉ mục nhanh các kết hợp k


11

Tôi đang xem lại một vấn đề cũ mà tôi đã làm việc cách đây một thời gian.

Một kịch bản điển hình là "3 bit được đặt trong một số nguyên 8 bit", tức là 00000111.

Tất cả các kết hợp duy nhất với 3 bit set có thể dễ dàng được tạo (theo thứ tự) bằng các vòng lặp lồng nhau. Điều tôi quan tâm là chỉ số ánh xạ <-> kết hợp, tức là "00001011" sẽ là kết hợp thứ hai (hoặc giá trị "1" trong chỉ mục dựa trên số không).

Cho đến nay, tôi đã chạy qua tất cả các kết hợp và lưu trữ chúng trong một bảng, làm cho chỉ mục tra cứu -> hội thoại trở thành thao tác O (1). Hướng khác là O (ln (n)) với tìm kiếm chia đôi.

Tuy nhiên, nhược điểm là điều này rõ ràng rất nặng về bộ nhớ nếu chúng ta tăng tên miền, đến mức không khả thi.

Điều gì sẽ là một cách đơn giản để tính toán kết hợp thứ n hoặc chỉ số cho một kết hợp nhất định? Thứ tự kết hợp sẽ tốt, nhưng không bắt buộc.



@MichaelT Liên kết của bạn không giải quyết được câu hỏi - lặp đi lặp lại qua các kết hợp không phải là vấn đề. Đây là về chỉ số ánh xạ và kết hợp. Cho "11001000", chỉ số (hoặc số đếm nếu bạn muốn) là gì? Mã nào thuộc chỉ số 1673?
Eiko

1
Ahh, trong trường hợp đó bạn có thể thấy OEIS hữu ích. Ví dụ, chuỗi 3,5,6,9,10,12,17,18 cho chúng ta tổng hai sức mạnh riêng biệt của hai , đó là một cách khác để nói "hai bit trên" trong thuật ngữ toán học. Các công thức khác nhau ở đó cho thấy nhiều cách tính toán giá trị thứ n.

1
Số nguyên 8 bit chỉ có 256 kết hợp của bất kỳ phần tử bit nào không đáng để lưu trữ (và sẽ chiếm ít không gian hơn bất kỳ mã thông minh nào). Số bit mục tiêu / ước tính của bạn là gì?
9000

1
Khi được đào lên ở nơi khác, đây được gọi là hệ thống số tổ hợp và Hackper của Gosper có thể làm điều đó trong O (1). Logic được thực hiện trong HACKMEM 175 và được giải thích trong bài đăng trên blog này ( bản gốc khá ngắn gọn).

Câu trả lời:


3

Tạo kết hợp thứ n được gọi là thuật toán "unranking". Lưu ý rằng hoán vị và kết hợp thường có thể được đánh đồng theo cách vấn đề được tham số hóa. Không biết chính xác vấn đề là gì, rất khó để đề xuất cách tiếp cận chính xác, và trên thực tế, đối với hầu hết các vấn đề tổ hợp thường có một số thuật toán xếp hạng / không xếp hạng khác nhau có thể.

Một tài nguyên tốt là "Thuật toán kết hợp" của Kreher và Stinson. Cuốn sách này có nhiều thứ hạng tốt và các thuật toán không được giải thích rõ ràng. Có nhiều tài nguyên nâng cao hơn, nhưng tôi muốn giới thiệu Kreher như một điểm khởi đầu. Như một ví dụ về thuật toán unrank, hãy xem xét những điều sau đây:

/** PKSUL : permutation given its rank, the slots and the total number of items
 *  A combinatorial ranking is number of the permutation when sorted in lexicographical order
 *  Example:  given the set { 1, 2, 3, 4 } the ctItems is 4, if the slot count is 3 we have:
 *     1: 123    7: 213   13: 312   19: 412
 *     2: 124    8: 214   14: 314   20: 413
 *     3: 132    9: 231   15: 321   21: 421
 *     4: 134   10: 234   16: 324   22: 423
 *     5: 142   11: 241   17: 341   23: 431
 *     6: 143   12: 243   18: 342   24: 432
 *  From this we can see that the rank of { 2, 4, 1 } is 11, for example. To unrank the value of 11:
 *       unrank( 11 ) = { 11 % (slots - digit_place)!, unrank( remainder ) }
 * @param rank           the one-based rank of the permutation
 * @param ctItems        the total number of items in the set
 * @param ctSlots        the number of slots into which the permuations are generated
 * @param zOneBased      whether the permutation array is one-based or zero-based
 * @return               zero- or one-based array containing the permutation out of the set { ctItems, 1,...,ctItems }
 */
public static int[] pksul( final int rank, final int ctItems, final int ctSlots, boolean zOneBased ){
    if( ctSlots <= 0 || ctItems <= 0 || rank <= 0 ) return null;
    long iFactorial = factorial_long( ctItems - 1 ) / factorial_long( ctItems - ctSlots );
    int lenPermutation = zOneBased ? ctSlots + 1 : ctSlots;
    int[] permutation = new int[ lenPermutation ];
    int[] listItemsRemaining = new int[ ctItems + 1 ];
    for( int xItem = 1; xItem <= ctItems; xItem++ ) listItemsRemaining[xItem] = xItem; 
    int iRemainder = rank - 1;
    int xSlot = 1;
    while( true ){
        int iOrder = (int)( iRemainder / iFactorial ) + 1;
        iRemainder = (int)( iRemainder % iFactorial );
        int iPlaceValue = listItemsRemaining[ iOrder ];
        if( zOneBased ){
            permutation[xSlot] = iPlaceValue;
        } else {
            permutation[xSlot - 1] = iPlaceValue;
        }
        for( int xItem = iOrder; xItem < ctItems; xItem++ ) listItemsRemaining[xItem] = listItemsRemaining[xItem + 1]; // shift remaining items to the left
        if( xSlot == ctSlots ) break;
        iFactorial /= ( ctItems - xSlot );
        xSlot++;
    }
    if( zOneBased ) permutation[0] = ctSlots;
    return permutation;
}

Đây là hoán vị unranking, nhưng như đã đề cập ở trên, trong nhiều trường hợp, bạn có thể chuyển đổi một kết hợp unrank thành một vấn đề hoán vị tương đương.

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.