题目
卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。
当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对 n=3 进行验证的时候,我们需要计算 3、5、8、4、2、1,则当我们对 n=5、8、4、2 进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这 4 个数已经在验证3的时候遇到过了,我们称 5、8、4、2 是被 3“覆盖”的数。我们称一个数列中的某个数 n 为“关键数”,如果 n 不能被数列中的其他数字所覆盖。
现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。
输入格式:
每个测试输入包含 1 个测试用例,第 1 行给出一个正整数 K (<100),第 2 行给出 K 个互不相同的待验证的正整数 n (1<n≤100)的值,数字间用空格隔开。
输出格式:
每个测试用例的输出占一行,按从大到小的顺序输出关键数字。数字间用 1 个空格隔开,但一行中最后一个数字后没有空格。
注意,关键数不是能覆盖数列内所有数字的数字,而是不能被数列中的其他数字所覆盖的数字。
解题
我自己写了一串代码,大概有50行,开始时有两个测试点一直过不了,也找不到原因。排查之后发现是冒泡排序法有问题,终于也算过了。我也看了大佬写的代码,读起来神清气爽,妙啊。也不知道我再练多少日子才能练出那样的功力。
我的代码
#include<iostream>
#include<cstring>
int a[105],b[105],c[15];
using namespace std;
int main(){
int n,i,j,s,t,r;
cin>>n;
s=0;t=0;r=0;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
for(i=0;i<n;i++){
cin>>a[i];
}
for(i=0;i<n;i++){
s=a[i];
while(s!=1){
for(j=0;j<n;j++){
if(a[j]==s) b[j]++;//每被覆盖一次记一次数(该数本身也算在内)
}
if(s%2==0) {s/=2;}
else {s=(3*s+1)/2;}
}
}
for(i=0;i<n;i++){
if(b[i]==1)
c[t++]=a[i];
}
for (i = 0; i < t; i++){
int key=0;
for (j = 0; j+1<t-i; j++){
if (c[j] > c[j+1]){
key=1;
r=c[j];c[j]=c[j+1];c[j+1]=r;
}
}
//如果 key 值为 0,表明表中记录排序完成
if (key==0) {
break;
}
}
for(i=t-1;i>=0;i--){
cout<<c[i];
cout<<(i==0?"\n":" ");
}
return 0;
}
大佬的代码来自铁肥宅
#include <stdio.h>
#include <stdlib.h>
int count[101];
void Callatz(int);
int cmp(const void *,const void *);
int main()
{
int i,K;
scanf("%d",&K);
int N[K],ans[K],n;
for(i=0 ; i<K ; i++)
{
scanf("%d",&N[i]);
Callatz(N[i]);
}
for(i=0,n=0 ; i<K ; i++)
if(count[N[i]] == 0)
ans[n++]=N[i];
qsort(ans,n,sizeof(int),cmp);
for(i=0 ; i<n ; i++)
printf("%s%d",i == 0 ? "" : " ",ans[i]);
}
void Callatz(int n)
{
while(n != 1)
{
n = n % 2 == 0 ? n / 2 : (3*n+1)/2;
if(n<=100)
count[n]++;
}
}
int cmp(const void *a,const void *b)
{
return *(int *)b-*(int *)a;
}
compar参数
compar参数指向一个比较两个元素的函数。比较函数的原型应该像下面这样。注意两个形参必须是const void *型,同时在调用compar 函数(compar实质为函数指针,这里称它所指向的函数也为compar)时,传入的实参也必须转换成const void *型。在compar函数内部会将const void *型转换成实际类型。
int compar(const void *p1, const void *p2);
如果compar返回值小于0(< 0),那么p1所指向元素会被排在p2所指向元素的前面;
如果compar返回值等于0(= 0),那么p1所指向元素与p2所指向元素的顺序不确定;
如果compar返回值大于0(> 0),那么p1所指向元素会被排在p2所指向元素的后面。
另附上qsort()函数的使用方法(转)
C++ qsort在"iostream" c在头文件stdlib.h中,strcmp在string.h中。下列例子默认从小到大排序即(a>b返回>0),反之从小到大排序
1、对int类型数组排序
int num[100];
int cmp ( const void *a , const void *b )
{
return *(int *)a - *(int *)b;
}
qsort(num,100,sizeof(num[0]),cmp);
2、对char类型数组排序(同int类型)
char strs[100];
int cmp( const void *a , const void *b )
{
return *(char *)a - *(int *)b;
}
qsort(strs,100,sizeof(strs[0]),cmp);
3、对double类型数组排序(特别要注意)
double dbs[100];
int cmp( const void *a , const void *b )
{
return *(double *)a > *(double *)b ? 1 : -1;
}
qsort(dbs,100,sizeof(dbs[0]),cmp);
4、对结构体一级排序
struct d
{
int a;
}arr[100]
int cmp( const void *a ,const void b)
{
return ((d )a)->a > ((d *)b)->b ? 1 : -1;
}
qsort(arr,100,sizeof(arr[0]),cmp);
5、对结构体二级排序
struct d
{
int x;
int y;
}arr[100];
//按照x从小到大排序,当x相等时按照y从大到小排序
int cmp( const void *a , const void *b )
{
struct d *c = (d *)a;
struct d *e = (d *)b;
return c->x != e->x?c->x - e->x:return e->y - c->y;
}
qsort(d,100,sizeof(d[0]),cmp);
6、对字符串进行排序
struct dict{
char str[100];
}dicts[100]
int cmp ( const void *a , const void b )
{
return strcmp( ((dict )a)->str , ((dict *)b)->str );
}
qsort(dicts,100,sizeof(dicts[0]),cmp);