尤拉計劃595題:增量隨機排序

lt發表於2017-03-19

隨機洗一副從 1 到 n編號的牌,使得每種排列都有相同的概率。

這些牌要使用以下技術排為升序︰

1.看牌的初始順序。如果它已經排好序,那麼就不需要採取進一步行動。否則,如果牌的任何子序列碰巧相對於彼此是在正確的位置 (升序且沒有縫隙),然後通過把牌連線在一起固定這些子序列。例如,對於 7張 牌,最初順序 4123756,標記 1,2 和 3 的牌將被連線在一起, 標記5 和 6的牌也是。

2.把牌拋向空中,'洗牌',但注意任何正確順序的牌都將保持連線,因此維持它們的順序。然後隨機挑選牌(或成捆的連線牌)。你應假定此隨機化是無偏的,儘管一些牌是單張的,而其他的是連線在一起的。

3.重複步驟 1 和 2,直到整副牌有序。

設 S(n) 是將牌片排序所需的洗牌次數的期望。因為在第一次洗牌前要檢查順序,S(1) = 0。已知 S(2) = 1 和 S(5) = 4213/871。

求 S(52),並把給你的答案四捨五入到小數點後 8位。

分析
如果是3張牌,洗一次出來的可能性有下面6種,每種的概率都是1/6.
1 2 3 =>已有序
1 3 2
2 1 3
2 3 1 ->[2 3] 1
3 1 2 ->3 [1 2]
3 2 1
上述未排好序的5種中,有2種發生了合併,下次洗牌都有1/2的概率排好序。其餘3種相當於初始值。

如果是4張牌,相當於在上述3張牌的基礎上,把4號牌插入4個可能的位置,其中每種3的排列都對應一種可以合併的情況,而第1種還是直接排序完成。

一個模擬程式,但每次執行差距有點大。

#include <cstdio>
#include <ctime>
#include <cstdlib>
#define d_p if(debug)printf
const int debug=0;

int blk_sort(const int NN)
{
    struct st
    {
        int h;
        int l;
    };
    st a[NN+1];
    st tmp[NN+1];
    int b[NN+1];
    for(int i=0; i<=NN; i++)
        b[i]=i;
    //init
    srand(time(0));
    for(int i=1; i<=NN; i++)
    {
        int t=rand()%(NN+1-i)+1;
        a[i].h=b[t];
        a[i].l=b[t];
        b[t]=b[NN+1-i]; // swap with last unused one
    }

    for(int i=1; i<=NN; i++)
    {
        d_p("[%d,%d] ",a[i].l,a[i].h);
    }
    int shuf_cnt=0;
    int blkno=NN;
    while(blkno>1)
    {
        for(int i=1; i<blkno; i++)
            if(a[i].h==a[i+1].l-1)
            {
                a[i].h=a[i+1].h;
                for(int j=i+1; j<blkno; j++)
                {
                    a[j].l=a[j+1].l;
                    a[j].h=a[j+1].h;
                }
                blkno--;
                i--; //continue merge next block
            }
        d_p("\n---->");
        for(int i=1; i<=blkno; i++)
        {
            d_p("[%d,%d] ",a[i].l,a[i].h);
            tmp[i].l=a[i].l;//copy to tmp
            tmp[i].h=a[i].h;
            a[i].l=a[i].h=0;
        }
        //shuffle tmp to new a
        for(int i=1; i<=blkno; i++)
        {
            int t=rand()%(blkno+1-i)+1;
            a[i].h=tmp[t].h;
            a[i].l=tmp[t].l;
            tmp[t].h=tmp[blkno+1-i].h; // swap with last unused one
            tmp[t].l=tmp[blkno+1-i].l;
        }
        shuf_cnt++;
        d_p("\nshff %d\n",shuf_cnt);
        for(int i=1; i<=blkno; i++)
        {
            d_p("[%d,%d] ",a[i].l,a[i].h);
        }
    }
    d_p("%d",shuf_cnt);
    return shuf_cnt;
}
int main()
{
    double test_cnt=1e5;
    int sum=0;
    for(int tm=1; tm<=test_cnt; tm++)
        sum+=blk_sort(52);
    printf("%lf",sum/test_cnt);
}

輸出

D:\>a
60.225190
D:\>a
51.528500
D:\>a
44.021820
D:\>a
56.847820
D:\>a
57.052220
D:\>a
59.092310
D:\>a
56.555870

相關文章