題目:
巡邏的士兵
時間限制:1000MS 內存限制:65536K
提交次數:217 通過次數:58
題型: 編程題 語言: G++;GCC
Description
有N個士兵站成一隊列, 現在需要選擇幾個士兵派去偵察。
爲了選擇合適的士兵, 多次進行如下操作: 如果隊列超過三個士兵, 那麼去除掉所有站立位置爲奇數的士兵,
或者是去除掉所有站立位置爲偶數的士兵。直到不超過三個戰士,他們將被送去偵察。現要求統計按這樣的方法,
總共可能有多少種不同的正好三個士兵去偵察的士兵組合方案。
注: 按上法得到少於三士兵的情況不統計。
1 <= N <= 2的32次方-1
輸入格式
有多行(可能有上百行,儘量優化代碼),每行一個數字N,最後一行是0
輸出格式
對每一行的數字N,輸出針對N的方案數
直到沒有數字
輸入樣例
10
4
0
輸出樣例
2
0
思路:
1,思路實際上就是遞歸,結束條件很明顯,當n<3時返回0,當n=3時返回1,其餘時候則分解爲留下奇數位和留下偶數位。而且,對於每一次的分解操作,實際上就是分爲奇數和偶數兩派,也就是兩個子集相交爲空,所以計算出來的結果沒有重複。
2,太慢怎麼辦,太慢就是由於有大量的重複計算,比如你7遞歸調用4,3。而你8遞歸調用4,4.你會發現有大量重複的計算。如何加快,那就記憶化,就是開一個數組將每次得到結果的值保存下來,以後再次調用的時候就直接return 數組,而不用遞歸了。
爲什麼是遞歸?遞歸會不會造成重和解?
#include<cstdio>
#include<cstring>
#include<cstdlib>
int a[100000002]={0};
int f(int N)
{
if(N<100000000&&a[N]>0)return a[N]; //如果已經被記錄,直接返回
if(N<3)return a[N]=0;
else if(N==3)return a[N]=1;
else //否則,計算並記錄
{
int t=f((N+1)/2)+f(N/2);
if(N<100000000)a[N]=t;
return t;
}
}
int main()
{
int N;
while(1)
{
scanf("%d",&N);
if(N==0)break;
printf("%d\n",f(N));
}
return 0;
}