POJ之1012

問題描述:
有k個壞人k個好人坐成一圈,前k個爲好人(編號1~k),後k個爲壞人(編號k+1~2k),現在從編號1開始報數,一直報到m,一
輪結束後,必須要求第m個報數的人死掉,而且他要是壞人,在他死掉之後繼續從他的下一個開始報數,也是從1開始報到m,
第m個是壞人,拉出去斃掉,直到壞人全部死去,好人全部留下,我們需要編程找到這個值m;
 
解題思路: 
推導時要注意2點:
第一:每輪都是以前一輪死掉的人的後一個人作爲“1”開始順序編號的
如:k=3  編號:1 2 3 4 5 6 
正確答案m=5
第一輪報數後,5號被殺掉,那麼以6號開始作爲下一輪的“1”重新編號,然後數到4,四號被殺掉,然後是6號被殺掉,結束!!
第二:f[i]=(f[i-1]+m)%(n-i);   (i>1) 這是網上一些地方給出的遞推公式,對於本題而言是不正確的。因爲這種遞推公式針對
的是從0開始報數的Joseph,本題是從1開始報數的,必須要變形,最後就是由於本題k值有限,只有13個值,那麼POJ的數據測試
就極有可能重複測試每個k值的結果,爲了節省總體時間,我們的程序只在第一次得到k值的時候計算m值,然後保存下來,當k值
再次出現時,就直接把保存的結果輸出,不再計算m。這是在服務器打表的處理。另外有了遞推的程序後,我們就知道了每個k值
對應的m值。此時追求0ms AC的同學可以利用遞推程序的結果,再寫一個程序,直接在程序裏面打表
int Joseph[]={0,2,7,5,30,169,441,1872,7632,1740,93313,459901,1358657,2504881,1245064};
<此題有參考某同學的······>

#include<iostream>
using namespace std;

int main(void)
{
	int Joseph[14]={0};  //打表,保存各個k值對應的m值

	int k;
	while(cin>>k)
	{
		if(!k)
			break;
		if(Joseph[k])
		{
			cout<<Joseph[k]<<endl;
			continue;
		}
		int n=2*k;  
		int ans[30]={0};  //第i輪殺掉 對應當前輪的編號爲ans[i]的人,每一輪都以報數爲“1”的人開始重新編號

		int m=1;    //所求的最少的報數
		for(int i=1;i<=k;i++)  //輪數
		{
			ans[i]=(ans[i-1]+m-1)%(n-i+1);   //n-i爲剩餘的人數
			if(ans[i]<k)  //把好人殺掉了,m值不是所求
			{
				i=0;
				m++;  //枚舉m值
			}
		}
		Joseph[k]=m;
		cout<<m<<endl;
	}
	return 0;
}


發佈了47 篇原創文章 · 獲贊 7 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章