描述
考慮下列算法:
1. input n
2. print n
3. if n = 1 then STOP
4. if n is odd then n <- 3n+1
5. else n <- n/2
6. GOTO 2
輸入:22,
打印序列:22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
假設對於所有整數值,算法可終止(打印到1時),但不知道假設是否爲真。對於所有的整數n,例如
給定輸入n,可能確定在打印到1時一共輸出的數字的個數,該個數成爲n的週期長度,對於上面的例子,22的週期長度爲16.
對於任意兩個數i,j,找到i,j之間的所有整數中,最大的週期長度。
輸入
輸入是一系列整數對i,j,每行一對整數。所有整數n,
輸出
對於每對輸入整數i,j,需要輸出i,j和[i,j]區間內的最大的週期長度。這三個數用至少一個空格分開,位於一行內。輸出的i,j要和輸入的順序相同。
輸入樣例
1 10
100 200
201 210
900 1000
輸出樣例
1 10 20
100 200 125
201 210 89
900 1000 174
思路
直接計算的話,由於數據計算量在10,000內,可以
打表的話,與直接計算只能節省重複區間的計算量,不會快很多
最快的算法是深度搜索+記憶優化(記憶優化相當於打表),適用於n爲更大的數時,作爲拓展瞭解一下吧。。。
注意:
1. 打印1本身也算在週期內
2. 每對數i,j不一定是i
1 直接計算
164K 16MS C 859B
#include <stdio.h>
int steps(n)
{
int count = 1;
while(n != 1)
{
if(n&1)//按位與運算,奇數的二進制末尾爲1,奇數&1結果爲1
{
//設 k = n/2, 則 3(2k+1)+1 = (3k+2)*2,減少一次迭代
n = n/2 * 3 + 2;
count += 2;
}
else
{
n /= 2;
++count;
}
}
return count;
}
int main()
{
int i,j,max,t,k,k_step;//t用於交換,k用於遍歷
int tmp_i,tmp_j;//用於保存輸入的i,j的順序
while(scanf("%d%d",&i,&j)==2)
{
tmp_i = i;
tmp_j = j;
if(i>j){
t = i;
i = j;
j = t;
}
max = steps(i);
for(k = i+1; k <= j; ++k)
{
k_step = steps(k);
if(max < k_step)
max = k_step;
}
printf("%d %d %d\n", tmp_i,tmp_j,max);
}
return 0;
}
2 打表
204K 0MS C 924B
#include <stdio.h>
int steps_arr[10001] = {0};//從1開始計數
void calcSteps()
{
int i,n;
for(i=1; i < 10001; ++i)
{
steps_arr[i] = 1;
n = i;
while(n!=1)
{
if(n&1){
n = n/2 * 3 + 2;
steps_arr[i] = steps_arr[i] + 2;
}
else
{
n /= 2;
steps_arr[i] = steps_arr[i] + 1;
}
}
}
}
int main()
{
int i,j,t,k,max;
int temp_i,temp_j;
calcSteps();
while(scanf("%d%d",&i,&j)==2)
{
temp_i = i;
temp_j = j;
if(i > j)
{
t = i;
i = j;
j = t;
}
max = steps_arr[i];
for(k = i+1; k <= j; ++k)
{
if(max < steps_arr[k])
max = steps_arr[k];
}
printf("%d %d %d\n",temp_i, temp_j, max);
}
return 0;
}
深度搜索+記憶優化
244K 0MS C 941B
#include <stdio.h>
int steps_arr[20001] = {0};
int dfs(int n)
{
if(n==1)
return 1;
if(n > 20000)
{
if(n&1)
return dfs(n/2 *3 + 2) + 2; //這裏就是深度搜索,向下遞歸一層
else
return dfs(n/2) + 1;
}
if(!steps_arr[n]) //沒有求過n的步數,則需要求(否則可以用上次返回的值【記憶】)
{
if(n&1)
return dfs(n/2 *3 + 2) + 2;
else
return dfs(n/2) + 1;
}
else
return steps_arr[n];
}
int main()
{
int i,j,max,k,t;
steps_arr[1] = 1;
for(i = 1; i < 10001; ++i)
{
steps_arr[i] = dfs(i);//打表,主要保存那些頻繁計算的數的步數
}
while(scanf("%d%d",&i,&j)==2)
{
printf("%d %d ",i,j);
max = 0;
if(i > j)
{
t = i;
i = j;
j = t;
}
for(k = i; k <= j; ++k)
{
if(max < steps_arr[k])
max = steps_arr[k];
}
printf("%d\n", max);
}
return 0;
}