1. 程式人生 > 實用技巧 >約瑟夫環總結

約瑟夫環總結

約瑟夫環

約瑟夫環算是比較經典的題目,我的解法是採用陣列模擬連結串列
通過例題來分析吧
洛谷P1996約瑟夫問題

AC程式碼

#include<stdio.h>
int pre[101],nxt[101];
int main(){
	int m,n;
	scanf("%d %d",&n,&m);
	int i,j,k;
	for (i=1;i<=n;i++){
		pre[i]=i-1;//存放當前點的上一點
		nxt[i]=i+1;//存放當前點的下一點
	}
	pre[1]=n;nxt[n]=1;//讓最後一點的下一點是第一點,第一點的上一點是最後一點,形成迴圈
	int now=n;//這樣才能使在等一下的迴圈一開始now=1;見這行下面的第四行,保證第一次now=nxt[now]後now==1
	int l,r;
	for (i=1;i<=n;i++){
		for (j=1;j<=m;j++){
			now=nxt[now];
		}
		printf("%d ",now);
		l=pre[now];r=nxt[now];
		nxt[l]=r;pre[r]=l;
                //將now這個點去掉,讓nxt[now]成為pre[now]的下一點,pre[now]成為nxt[now]的上一點,有點拗口,可以看下面的一張圖(有點醜哈哈)
	}
	return 0;
}

2 出色的物理引擎 (100分)
卡羅拉最近沉迷於ark遊戲,遊戲中的地圖上有n個浮空的石頭圍成了一圈,在優秀的物理引擎支援下,這些石頭會自動落下。她發現石頭落下的順序是有規律的。一共有n個石頭,從第一塊石頭開始數,數到第m個石頭,那塊就是第一個落下的石頭;之後從第一個落下的石頭後一個重新從1開始數,同樣數到第m個石頭,那個就是第二個落下的石頭;以此類推。為了方便,對這些石頭從1開始編號。卡羅拉現在想知道最後落下的是那一塊石頭?

輸入格式:

輸入包含兩個整數n和m (1<=m,n<=1000)。

輸出格式:

輸出一 個整數,代表最後落下的石頭的編號。

輸入樣例:

10 3

輸出樣例:

4

這題的處理方法和上面基本一模一樣,只有在輸出時不同,如果理解了上面那一題,可以拿這題練練手,就不再繼續解釋了(不好意思哈有點懶
AC程式碼

#include<string.h>
#include<stdio.h>
#include<stdlib.h>
int pre[10007],nxt[10007];
int main()
{
	int i,j,k,l,r,m,n;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		pre[i]=i-1,nxt[i]=i+1;
	}
	nxt[n]=1,pre[1]=n;
	k=n; 
	
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			k=nxt[k];
		}
		if (i==n) {
			printf("%d",k);
			break;
		}
		l=pre[k],r=nxt[k];
		pre[r]=l,nxt[l]=r;		
	}
	return 0;
}

洛谷P1145約瑟夫

#include<stdio.h>
int main(){
	int k,n;
	scanf("%d",&k);
	int m=k;
	int i,j,temp=1;
	while(temp){
		//假設序號為0~k-1都是好人,k~2*k-1都是壞人 
		m++;// m至少要大於1 
		int bekilled=0;//第一個被殺的序號 
		for (i=0;i<k;i++){
			//按照假設,序號為0~k-1都是好人,k~2*k-1都是壞人  
			bekilled=(bekilled+m-1)%(2*k-i);//下一個被殺的序號 
			if (bekilled<k){//如果被殺者序號小於k,則好人被殺,不符合題意 
				break;
			}
			if (i==k-1){//當被殺者(前面的程式碼保證了被殺的都是壞人)達到 k人,達到題設要求 
				temp=0;
			}
		}
	}
	printf("%d",m);
	return 0;
}