poj 1207 The 3n + 1 problem
當我看到題目的時候我就感覺到這是一道徹徹底底的水題,因為很像A+B的作風。。。
但是看完題目我心裏想了想:應該沒有那麼水吧,可能還是要優化的,暴力可能會TLE。。。
但是我暴力過了以後我這樣想:。。。。。。。
下麵摘抄了一點文字說明:
大致題意:
根據給定的算法,可以計算一個整數的循環數
現在給定一個區間,計算這個區間的所有數的循環數,把最大的循環數輸出
PS:輸出的是整數A的循環數,而不是輸出整數A
解題思路:
注意的隻有一點:
輸入的兩個區間端點不一定是從小到大輸入的,因此要先對這兩個數排一下序。
【純暴力】AC的代碼:
#include<stdio.h>
int Process(int i)
{
int count=1;
while(i!=1)
{
if(i%2)
i=3*i+1;
else
i/=2;
count++;
}
return count;
}
//這題居然可以暴力過。。。我不解釋
int main()
{
int a,b;
while(scanf("%d%d",&a,&b)!=EOF)
{
int x=a<b?a:b;
int y=a>b?a:b;
int Max=0;
for(int i=x;i<=y;i++)
{
int temp=Process(i);
if(Max<temp)
Max=temp;
}
printf("%d %d %d\n",a,b,Max);
}
return 0;
}
寫寫自己”不暴力“的思路:
要維護兩個集合
1. 每個數當然最好有一個自己的數組專門存循環節的長度,因為很可能區間有重疊。。。
2. 另外一個集合 【鏈表】就是把 循環序列 都存起來,因為循環節很可能就是重複的,比如知道 4 的長度是 3 ,那 8/2 以後就是 4 ,就不用算了,長度就是3+1=4;這樣就要每次檢查一次,如果有就結束循環,否則如果沒有就 插入那個序列,這就涉及 搜索 ,當然最好用 二分。。。
這樣就不算水了。。。
最後我並不是用這個解法。。。我是維護了一個Trace數組,相當於維護路徑。。。之後再處理路徑上的值的循環節。。。在電腦上對了,但是一直Runtime Error。。。改了數組上下界無數次也不行。。。後來直接改成 int 數組的極大值,AC了
附代碼:
#include <stdio.h>
//自動初始化為0
int Num[99999999];
int Trace[99999999];
void RecordTrace(int count)
{
int i;
for(i=count;i>=1;i--)
{
if(Num[Trace[i]]!=0)
continue;
else
Num[Trace[i]]=i;
}
}
int Process(int pos)
{
int count=1;
Trace[1]=pos;
while(pos!=1)
{
if(pos%2)
{
pos=3*pos+1;
if(Num[pos]!=0)
{
count+=Num[pos];
RecordTrace(count);
return count;
}
else
{
count++;
Trace[count]=pos;
}
}
else
{
pos/=2;
if(Num[pos]!=0)
{
count+=Num[pos];
RecordTrace(count);
return count;
}
else
{
count++;
Trace[count]=pos;
}
}
}
return count;
}
int main()
{
int a,b;
while(scanf("%d%d",&a,&b)!=EOF)
{
int x=a<b?a:b;
int y=a>b?a:b;
int max=-1;
int i,tmp;
for(i=x;i<=y;i++)
{
if(Num[i]!=0)
{
if(Num[i]>max)
max=Num[i];
}
else
{
tmp=Process(i);
if(tmp>max)
max=tmp;
}
}
printf("%d %d %d\n",a,b,max);
}
return 0;
}
另:附上一個不水的解法
POJ 1207 HDOJ/HDU 1032 3n+1數鏈問題 絕對不水的解法
最後更新:2017-04-03 14:53:50