1. 程式人生 > >C語言解決約瑟夫問題演算法

C語言解決約瑟夫問題演算法

據說著名猶太曆史學家 Josephus有過以下的故事:在羅馬人佔領喬塔帕特後,39 個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧願死也不要被敵人抓到,於是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下一個重新報數,直到所有人都自殺身亡為止。然而Josephus 和他的朋友並不想遵從。首先從一個人開始,越過k-2個人(因為第一個人已經被越過),並殺掉第k個人。接著,再越過k-1個人,並殺掉第k個人。這個過程沿著圓圈一直進行,直到最終只剩下一個人留下,這個人就可以繼續活著。問題是,給定了和,一開始要站在什麼地方才能避免被處決?Josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲

。這就是著名的約瑟問題的由來。

約瑟夫問題是個有名的問題:N個人圍成一圈,從第一個開始報數,第M個將被殺掉,最後剩下一個,其餘人都將被殺掉。例如N=6,M=5,被殺掉的順序是:5,4,6,2,3,1。

我寫的解決約瑟夫問題的演算法如下:

void NewJosephus (int n,int order,int remain)
{
    int count=1;
    int i;
    J *p=CreateLink(n);//建立迴圈單鏈表,並將頭指標返回給p
    J *q=p->next;//q初始指向第一個節點
    J *m=p;//m初始指向頭指標
    if(remain>=n)
    {
        printf("錯誤/n");
    }
    else
    {
        while(p!=NULL)
        {
            if(count==order)
            {
                if(m==q)
                {
                    break;
                }
                m->next=q->next;
                printf("%d ",q->data);
                free(q);
                q=m->next;
                count=1;
                n-=1;
                if(n==remain)
                {
                    break;
                }
            }
            else
            {
                m=q;
                q=q->next;
                count+=1;
            }
        }
        p->next=q;
        printf("\n剩下的人為:\n");
        for(i=0;i<remain;i++)
        {
            printf("%d ",q->data);
            q=q->next;
        }
    }
}

其中,n為人的總數,order即為第幾個人被pass掉,remain是剩下人的個數。

建立單迴圈連結串列的演算法如下:

J* CreateLink(int n)
{
    int i;
    J *head,*p,*q;
    head=(J*)malloc(sizeof(J));
    head->next=NULL;
    q=head;
    for(i=1;i<=n;i++)
    {
        p=(J*)malloc(sizeof(J));
        p->data=i;
        q->next=p;
        p->next=NULL;
        q=p;
    }
    q->next=head->next;
    return head;
}
輸入41,3,2(即求原始的約瑟夫問題的解),結果如圖


如果有不足之處,還望大家指出!