1. 程式人生 > >小模擬特訓(UVA133 救濟金髮放)約瑟夫問題變形版

小模擬特訓(UVA133 救濟金髮放)約瑟夫問題變形版

問題描述

n(n<20)個人站成一圈,逆時針編號為1~n。 有兩個官員,A從1開始逆時針數,B從n開始順時針數。 在每一輪中,官員A數k個就停下來,官員B數m個就停下來(注意有可能兩個官員停在同一個人上)。 接下來被官員選中的人(1個或者2個)離開隊伍。輸入n,k,m輸出每輪裡被選中的人的編號(如果有兩個人,先輸出被A選中的)。 例如,n=10,k=4,m=3,輸出為4 8, 9 5, 3 1, 2 6, 10, 7。 注意:輸出的每個數應當恰好佔3列。

解題思路:本題是約瑟夫問題的變形版,這裡給出的是演算法競賽入門經典作者劉汝佳的程式碼。此版本簡潔明瞭,幹練有效,值得我們學習、效仿。

下面直接給出程式碼:

#include<stdio.h>
#define maxn 25
int a[maxn];              //存放人群編號,無人為0 
int n,k,m;

int go(int p,int d,int ncount)      //p表示起點,d=1為逆時針,d=-1為順時針,ncount為數數次數。 
{
	while(ncount--)
	{
		do
		{
			p=(p+d+n-1)%n+1;        //這裡因為下標從1-n,所以加n-1再%n,如果下標從0-n-1,加n再%n。為保證
			                         // 輸出的p下標也是1-n,最後還要加1. 
		}while(a[p]==0);             //為0跳過 
	}
	return p;
}

int main()
{
	while(scanf("%d%d%d",&n,&k,&m)!=EOF)
	{
		for(int i=1;i<=n;i++)      //下標從1-n 
		{
			a[i]=i;
		}
		int left=n;
		int p1=n,p2=1;            //逆時針起始為n不為1,順時針起始為1不為n 
		while(left)
		{
			p1=go(p1,1,k);
			p2=go(p2,-1,m);
			printf("%d",a[p1]);
			left--;
			if(p2!=p1)
			{
				left--;
				printf(" %d",a[p2]);
			}
			a[p1]=a[p2]=0;
			if(left) printf(",");
		}
		printf("\n");
	}
	return 0;
}