题目如下:
这是1001 3n+1的进阶版。这里是3n+1猜想:
我们来比较一下二者的不同,1001就是简单的验证3n+1,求其中到达一的步数。而1005提出了一个新的概念:关键数字。好,那么重点来了,关键数字是什么?这里根据题目条件,比如当你验证5的猜想时
5 8 4 2 1,那么接下来当你需要验证8 4 2时,可以直接得出满足条件,因为你在之前验证5时的过程中出现了这几个数。但是如果没有出现,那么你不得不判断一下这个数是否满足猜想,比如7。
了解之后我们来看这个题,要求输入一段数字。寻找其中的关键数字,我第一次的代码如下,思路都在注释,比较清晰了:
//为了避免重复计算,可以记录下递推过程中遇到的每一个数
//每个测试输入包含 1 个测试用例,第 1 行给出一个正整数 K (<100),第 2 行给出 K 个互不相同的待验证的正整数 n (1<n≤100)的值,数字间用空格隔开
//你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
//数组开大
int s[100005];//s记录数组.被记录记为1,未被记录为0
int a[100005];//记录关键数字的数组,要进行排序(从大到小
int cnt;
//比较函数用
bool cmp(int a, int b) {
return a > b;//从大到小
}
/*/判断是否是最后一个
int check_flag(int n){
if(n != 1) return 1;
else return 0;
}*/
//判断输出空格
void check_space(int flag,int cnt){
cout << a[flag];//输出
if(flag != cnt - 2) cout << " ";//不是最后一位,那么输出空格
}
//验证3n+1
void check(int num){
//3n+1猜想
int step = num;//一个替身
s[num] = 1;//num开始验证,标记先标记
while(step != 1){
if(step % 2 == 0) step /= 2;//偶数
else step = (3 * step + 1) / 2;//奇数
s[step] = 1;//被记录,标记一次
}
}
int main(){
int n,num;//
cin >> n;
while(n --){
cin >> num;
if(s[num] == 0){
a[cnt ++] = num;//未在s数组中标记即这个num是关键数字,存在a数组中
check(num);//关键数字进行验证,但是第一个输入的数字不是
}
}
//因为第一个输入验证猜想的数不是关键数字,此时他在as数组的第一位,我们将他移除
//此时关键数字数量为cnt-1
for(int i = 0;i < cnt; i++){
a[i] = a[i + 1];
}
sort(a, a + cnt - 1, cmp);//从大到小排序
//for(int i = 0; i < cnt - 1; i ++) cout << a[i] << endl;
//cout << cnt - 1 << endl;
for(int i = 0; i < cnt - 1; i ++){
check_space(i,cnt);
}
cout << endl;
return 0;
}
//一行中最后一个数字后没有空格
/*
6
3 5 6 7 8 11
*/
虽然可以过部分测试点,但毫无疑问是错的,我想了很久不,在朋友的提醒下找到了错误。那就是
//因为第一个输入验证猜想的数不是关键数字,此时他在as数组的第一位,我们将他移除 //此时关键数字数量为cnt-1 for(int i = 0;i < cnt; i++){ a[i] = a[i + 1]; }这一段代码,其中有一点是样例中第一个输入的3不是关键数字,所以我直接在记录数组排序前将第一个数也就是输入的3给剔除了。但是出现了很严重的错误,那就是谁说得第一个就不能说关键数字呢?代码逻辑出现了错误,之所以出现这个错误,我发现是我的理解吧出现错误,他的关键数字是针对整个数字,后面有一个数字的验证覆盖了前面的数字,那么前面的数字就不是关键数字了。他并不是按照输入顺序来的。那么一切重来,但基本的思想不变,那就是用一个数组去记录这个数字被覆盖了没有,用不用自己去验证。先不对数组做任何处理,所有的都循环完之后,再去寻找没有被标记的数组位置,那就是关键数字了,代码如下:
//为了避免重复计算,可以记录下递推过程中遇到的每一个数
//每个测试输入包含 1 个测试用例,第 1 行给出一个正整数 K (<100),第 2 行给出 K 个互不相同的待验证的正整数 n (1<n≤100)的值,数字间用空格隔开
//你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
//数组开大
int b[100005];//存输入的数组
int s[100005];//s记录数组.被记录记为1,未被记录为0
int a[100005];//记录关键数字的数组,要进行排序(从大到小
int cnt;
//比较函数用
bool cmp(int a, int b) {
return a > b;//从大到小
}
/*/判断是否是最后一个
int check_flag(int n){
if(n != 1) return 1;
else return 0;
}*/
//判断输出空格
//验证3n+1
void check(int num){
//3n+1猜想
int step = num;//一个替身
while(step != 1){
if(step % 2 == 0) step /= 2;//偶数
else step = (3 * step + 1) / 2;//奇数
s[step] = 1;//被记录,标记一次
}
}
int main(){
int n;//
cin >> n;
for(int i = 0; i < n; i ++)
cin >> b[i];//输入数组
for(int i = 0; i < n; i ++){
int temp = b[i];
check(temp);//检查验证
}
//sort(b,b + n,cmp);
for(int i = 0; i < n; i++){
if(!s[b[i]])
a[cnt ++] = b[i];//关键数字存进去
}
sort(a,a + cnt,cmp);
cout << a[0];
for(int i = 1; i < cnt; i ++)
cout << " " << a[i];
return 0;
}
//一行中最后一个数字后没有空格
/*
6
3 5 6 7 8 11
*/
成功AC,困扰我一天的题目被解决了,真是可以被让人放心睡觉,眠了。 题目链接