功能:
我们需要一种数据结构,用来记录递推过程中遇到的每一个数,但具体会有多少数,无法提前确定,所以就无法用数组来定义。
C++中有一种数据结构叫做单向链表结构,可以用它来存放递推过程中遇到的每一个数。
struct node{
int data;
node* next;
};
我们先递推下用例中输入的数:
被3“覆盖”的数:5,8,4,2
被5“覆盖”的数:8,4,2
被6“覆盖”的数:3,5,8,4,2
被7“覆盖”的数:11,17,26,13,20,10,5,8,4,2
被8“覆盖”的数:4,2
被11“覆盖”的数:17,26,13,20,10,5,8,4,2
被100“覆盖”的数:50,25,38,19,29,44,22,11,17,26,13,20,10,5,8,4,2
可以发现,只要依次对输入的数进行递推,并把并把递推过程中遇到的数存储到链表中(除1和这个数本身外),那么,这个数只要这个数不在链表中,它就是关键字。
程序设计:
1.输入格式:
每个测试输入包含 1 个测试用例,第 1 行给出一个正整数 K (<100),第 2 行给出 K 个互不相同的待验证的正整数 n (1<n≤100)的值,数字间用空格隔开
待验证的正整数最大为100,而被100“覆盖”数,有17个,我们可以设b的数组长度为20.
int i,k,b[20];//①临时存放被覆盖的数 ②数组b用来存放关键字,用于输出
cin>>k;
int *a = new int[k]; if(!a) exit(3); //动态分配空间,数组a用来存放k个互不相同待验证的正整数
for(i = 0;i < k;i++)
cin>>a[i];
2.创建链表
在生成链表之前,我们先做一些准备工作。
(1)求递推值:positiveSeq(int b[],int m)
函数功能:将被m“覆盖”的数存储在数组b中,并返回数组b的长度。
int positiveSeq(int b[],int m){
int n = 0;
while(m > 2){
if(m % 2 == 0) m = m / 2;
else m = (3 * m + 1) / 2;
if(n < 20) b[n++] = m;
}
return n;
}
(2)数组b逆序存储:negativeSeq(int b[],int n)
函数功能:将数组b逆序存储,n为数组b的长度。
比如:b[]={5,8,4,2},在调用negativeSeq(b,4)之后,b[] = {2,4,8,5}
void negativeSeq(int b[],int n){
for(int i = 0;i < n / 2;i++){
int j = n - i - 1;
swap(&b[i],&b[j]);
}
}
这里用到的swap()函数,比较常见,就不多做介绍了。
void swap(int *p1,int *p2){
int temp = *p2;
*p2 = *p1;
*p1 = temp;
}
(3)创建并生成链表:Insert(node *head,int m)
函数功能:新建一个结点n,将m的值赋给结点n,并将该结点插入head中,返回head。
node* Insert(node *head,int m){
node *p = NULL,*n = NULL;
n = new node;
n->data = m;
if(head == NULL) {head = n;n->next = NULL;}
p = head;
while(p->next != NULL && p->data != n->data)
p = p->next;
if(p->data != n->data){n->next = head;head = n;}
return head;
}
在主函数中,生成链表的过程如下:
for(i = 0;i < k;i++){
n = positiveSeq(b,a[i]);
negativeSeq(b,n);
for(j = 0;j < n;j++)
head = Insert(head,b[j]);
}
生成链表后,就要根据数组a[]来查找关键字,我们先创建一个函数,帮助查找关键字。
3.查找关键字:searchKey(node *head,int m)
函数功能:在head指向的链表中查找m,若链表中有m,则返回-1,否则直接返回m
int searchKey(node *head,int m){
node *p;
p = head;
while(p->next != NULL && p->data != m)
p = p->next;
if(p->data == m) return -1;
else return m;
}
主函数中的查找过程如下:
for(i = 0,n = 0;i < k;i++){
m = searchKey(head,a[i]);
if(m != -1) b[n++] = m;
}
因为要求按从大到小的顺序输出,所以我们还要对数组b进行排序,从大到小排序
主函数中的排序过程如下:
for(i = 0;i < n;i++){
for(j = i + 1;j < n;j++){
if(b[i] < b[j])
swap(&b[i],&b[j]);
}
}
4.输出:
一切准备就绪,我们可以用for循环遍历数组b直接输出。但是,输出又有了要求:数字间用 1 个空格隔开,但一行中最后一个数字后没有空格。,所以要用if…else分别输出。
主函数中的输出过程如下:
for(i = 0;i < n;i++){
if(i == n - 1) cout<<b[i]<<endl;
else cout<<b[i]<<' ';}
}
完整的代码如下:
#include<iostream>
using namespace std;
struct node{
int data;
node *next;
};
void swap(int *p1,int *p2){
int temp = *p2;
*p2 = *p1;
*p1 = temp;
}
int positiveSeq(int b[],int m){
int n = 0;
while(m > 2){
if(m % 2 == 0) m = m / 2;
else m = (3 * m + 1) / 2;
if(n < 20) b[n++] = m;
}
return n;
}
void negativeSeq(int b[],int n){
for(int i = 0;i < n / 2;i++){
int j = n - i - 1;
swap(&b[i],&b[j]);
}
}
node* Insert(node *head,int m){
node *p = NULL,*n = NULL;
n = new node;
n->data = m;
if(head == NULL) {head = n;n->next = NULL;}
p = head;
while(p->next != NULL && p->data != n->data)
p = p->next;
if(p->data != n->data){n->next = head;head = n;}
return head;
}
int searchKey(node *head,int m){
node *p;
p = head;
while(p->next != NULL && p->data != m)
p = p->next;
if(p->data == m) return -1;
else return m;
}
int main(){
int i,j,n,k,m;
int b[20];
node *head = NULL;
cin>>k;
int *a = new int[k]; if(!a) exit(3);
for(i = 0;i < k;i++)
cin>>a[i];
for(i = 0;i < k;i++){
n = positiveSeq(b,a[i]);
negativeSeq(b,n);
for(j = 0;j < n;j++)
head = Insert(head,b[j]);
}
for(i = 0,n = 0;i < k;i++){
m = searchKey(head,a[i]);
if(m != -1) b[n++] = m;//76行
}
for(i = 0;i < n;i++){
for(j = i + 1;j < n;j++){
if(b[i] < b[j])
swap(&b[i],&b[j]);
}
}
for(i = 0;i < n;i++){
if(i == n - 1) cout<<b[i]<<endl;
else cout<<b[i]<<' ';}
}
代码可以通过测试,但是有一个小问题,如果将第76行的
if(m != -1) b[n++] = m;
改成
if(m != -1 && n < 20) b[n++] = m;
就会有一个测试点错误,提示“您的程序未能对评测系统的数据返回正确的结果”。这个想不通哦,数组b的长度在定义时已经确定了,但是显式的写出n < 20这个限制条件,反而有了问题。