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