这套题有一点难度,不过没关系,只要你认真学习、全力思考,困难将会在笔墨之间,消散。
一.代数
题面
7.设X、Y、Z分别代表三进制下的一位数字,若等式XY+ZX=XYX在三进制下成立,那么同样在三进制下,等式XY∗ZX=()也成立。
A YXZ
B ZXY
C XYZ
D XZY
答案解析
我们分析一下就可以了:
1.先看第一位,不可能发生进位,又X+Y=X。所以,Y就等于0;
2.再看第二位,X+Z=XY。因为Y=0,所以X+Z=X0。
2.1 我们可以假设X=1,Z=2(三进制,X不等于Y不等于Z),发现 1+2=10,成立;
2.2 又设X=1,Z=2,发现2+1=10≠20,因此不成立。
因此,X=1,Z=2;
综上所述,X=1,Y=0,Z=2,
所以XY*ZX=10*21=210=YXZ
故选B。
二.进制转换
题面
13.一个自然数在十进制下有n位,则它在二进制下的位数与( )最接近。
A 5n
B n * log2(10)
C 10 * log2(n)
D 10^n * log2(n)
答案解析
十进制转二进制一般使用除二取余法。
可以举例尝试,
①两位数37(2位),转换成二进制是100101(6位)
A项:5*2=10(位)
B:项 n*log 210≈6.64(位)
C项: 10*log 2n=10(位)
D项:10 nlog 2n =100(位)
②三位数176(3位),转换成二进制是10110000(8位)
A项:5*3=15(位)
B:项:n*log 210≈10.53(位)
C项: 10*log 2n≈15.8(位)
D项:10 nlog 2n =1584.96(位)
没有好的证明方法,通过举例可以看出,B项是最接近的。
三.双向链表
题面
双向链表中有两个指针域llink和rlink,分别指向该结点的前驱及后继。设p指向链表中的一个结点,它的左右结点均非空。现要求删除结点p,则下面语句序列中错误的是( )。
A.p->rlink->llink = p->rlink;
p->llink->rlink = p->llink; delete p;
B.p->llink->rlink = p->rlink;
p->rlink->llink = p->llink; delete p;
C.p->rlink->llink = p->llink;
p->rlink->llink->rlink = p->rlink; delete p;
D.p->llink->rlink = p->rlink;
p->llink->rlink->llink = p->llink; delete p;
答案解析
看似很复杂,实际上只要学习一下链表相关知识就行了。
用排除法做,就行了。
A的第一行的结果是使得结点p的后继结点的前驱指向了它本身,逻辑错误。
故选A。
另:我以前写过一篇有关链表的文章,不会链表的建议看一下:【数据结构】链表 详解
四.队列
题面
队列快照是指在某一时刻队列中的元素组成的有序序列。例如,当元素1、2、3入队,元素1出队后,此刻的队列快照是"2 3"。当元素2、3也出队后,队列快照是"",即为空。现有3个正整数元素依次入队、出队。已知它们的和为8,则共有_________种可能的不同的队列快照(不同队列的相同快照只计一次)。例如,"5 2 1"、"4 2 2"、""都是可能的队列快照;而"7"不是可能的队列快照,因为剩下的2个正整数的和不可能是1。
答案解析
分几个步骤得到答案。
①有序枚举3个正整数可能的组合(1,1,6)(1,2,5)(1,3,4)(2,2,4)(2,3,3)。
②分成两类: 其中一类包含两个相同的数字,(1,1,6)(2,2,4)(2,3,3)每个可以形成8种队列快照。以(1,1,6)为例,(1)(6)(1,1)(1,6)(6,1)(1,1,6)(1,6,1)(6,1,1);
另一类三个数字互不相同,(1,2,5)和(1,3,4)每个可以行程15种队列快照。以(1,2,5)为例(1)(2)(5)(1,2)(2,1)(1,5)(5,1)(2,5)(5,2)(1,2,5)(1,5,2)(2,1,5)(2,5,1)(5,2,1)(5,1,2)。
那么一共有3×8+2×15=543×8+2×15=54种,但是存在重复和遗漏。
③重复:单个数字的快照(1)重复了2次,(2)重复了2次, (3)重复了1次,(4)重复了1次,去掉重复后剩54−2−2−1−1=4854−2−2−1−1=48种;
④遗漏:遗漏了空的快照,加上后有48+1=4948+1=49种;
一共有49种可能的不同的队列快照。
五.哥德巴赫猜想
题面
完善程序:
(哥德巴赫猜想)哥德巴赫猜想是指,任一大于2的偶数都可写成两个质数之和。迄今为止,这仍然是一个著名的世界难题,被誉为数学王冠上的明珠。试编写程序,验证任一大于2且不超过n的偶数都能写成两个质数之和。#include <iostream> using namespace std; int main() { const int SIZE = 1000; int n, r, p[SIZE], i, j, k, ans; bool tmp; cin>>n; r = 1; p[1] = 2; for (i = 3; i <= n; i++) { [ ① ]; for (j = 1; j <= r; j++) if (i % [ ② ] == 0) { tmp = false; break; } if (tmp) { r++; [ ③ ] ; } } ans = 0; for (i = 2; i <= n / 2; i++) { tmp = false; for (j = 1; j <= r; j++) for (k = j; k <= r; k++) if (i + i == [ ④ ] ) { tmp = true; break; } if (tmp) ans++; } cout<<ans<<endl; return 0; }
若输入n为2010,则输出[ ⑤ ]时表示验证成功,即大于2且不超过2010的偶数都满足哥德巴赫猜想。
答案解析
根据直觉,我们可以知道,第一个循环求的是3-n里面所有的质数。
而由此可得,tmp标记的是当前的i是不是质数(true是,false非)
在①时,tmp需要初始化,变为1。
所以,①填的是:tmp=1或tmp=true或其他等价写法。
同时,p数组存的是质数,r是质数的个数,又因为i>p[j],且p[j]为质数,直接用i除p[j],这样就可以很快判断i是不是质数。
所以,第二题答案是p[j]
第三空:如果tmp仍为true,说明当前的i为质数,要记录新的质数了。因为记录质数个数的r已经加过一了(留出了位置),因此只需要将i赋值到p[r]即可即可。
所以,第三题答案是p[r]=i;
第四空:要判断2∗i(偶数)是否可以等于两质数(p[j]+p[k])之和
所以,第四题答案是p[j]+p[k]
第五空:若大于2且小于等于2010的偶数(有1004个)均可表示为两个质数之和,则应统计出1004个,输出的ans正是用于统计符合要求的偶数个数,所以填1004。
所以,第五题答案是1004.
六
完善程序:
(过河问题)在一个月黑风高的夜晚,有一群人在河的右岸,想通过唯一的一根独木桥走到河的左岸。在这伸手不见五指的黑夜里,过桥时必须借助灯光来照明,很不幸的是,他们只有一盏灯。另外,独木桥上最多承受两个人同时经过,否则将会坍塌。每个人单独过桥都需要一定的时间,不同的人需要的时间可能不同。两个人一起过桥时,由于只有一盏灯,所以需要的时间是较慢的那个人单独过桥时所花的时间。现输入(2≤n<100)和这n个人单独过桥时需要的时间,请计算总共最少需要多少时间,他们才能全部到达河的左岸。 例如,有3个人甲、乙、丙,他们单独过桥的时间分别为1、2、4,则总共最少需要的时间为7。具体方法是:甲、乙一起过桥到河的左岸,甲单独回到河的右岸将灯带回,然后甲、丙再一起过桥到河的左岸,总时间为2+1+4=72+1+4=7。#include <iostream> using namespace std; const int SIZE = 100; const int INFINITY = 10000; const bool LEFT = true; const bool RIGHT = false; const bool LEFT_TO_RIGHT = true; const bool RIGHT_TO_LEFT = false; int n, hour[SIZE]; bool pos[SIZE]; int max(int a, int b) { if (a > b) return a; else return b; } int go(bool stage) { int i, j, num, tmp, ans; if (stage == RIGHT_TO_LEFT) { num = 0; ans = 0; for (i = 1; i <= n; i++) if (pos[i] == RIGHT) { num++; if (hour[i] > ans) ans = hour[i]; } if ([ ① ]) return ans; ans = INFINITY; for (i = 1; i <= n - 1; i++) if (pos[i] == RIGHT) for (j = i + 1; j <= n; j++) if (pos[j] == RIGHT) { pos[i] = LEFT; pos[j] = LEFT; tmp = max(hour[i], hour[j]) +[ ② ]; if (tmp < ans) ans = tmp; pos[i] = RIGHT; pos[j] = RIGHT; } return ans; } if (stage == LEFT_TO_RIGHT) { ans = INFINITY; for (i = 1; i <= n; i++) if ([ ③ ]) { pos[i] = RIGHT; tmp =[ ④ ]; if (tmp < ans) ans = tmp; [ ⑤ ]; } return ans; } return 0; } int main() { int i; cin>>n; for (i = 1; i <=n; i++) { cin>>hour[i]; pos[i] = RIGHT; } cout<<go(RIGHT_TO_LEFT)<<endl; return 0; }
解析:
在本题中所有人初始都在右边,需要从右走到左。LEFT表示在左边,用true代替,
LEFT TO RIGHT表示从左往右用true代替,RIGHT TO LEFT表示从右往左用false代替,go函数()分为两部分,一是从右往左走,一是从左往右走,最后的状态肯定是最后两个人从右往左走。
从右往左:第25~33行的是在寻找目前在右边的人的最长过桥时间ans和统计右边的人数num,当num<=2时,右边人全部走到左边任务结束了;第34~47行是通过递归将问题规模缩小,此次过桥时间+未知的后续过桥时间。
从左往右:显然只需要一个人,除了人数与从右往左走完全相同,判断人是否在左边,在就让他走到右边,将状态赋值为RIGHT,递归,再将状态改回LEFT。
①num<=2,由题意下一行可以直接return ans
,说明此时已到达“基础情况”,即<=2num<=2(基础情况:只剩下两个人一趟可以走完);
②go(LEFT_TO_RIGHT)
,使用()go()函数,即go(LEFT_TO_RIGHT)
,即进入回溯;
③pos[i]==LEFT
,说明此时在左岸;
④hour[i]+go(RIGHT_TO_LEFT)
,此时tmp暂存值为已有的hour[i]加上go(RIGHT_TO_LEFT)
所需时间;
⑤pos[i]=LEFT
,此时将位置pos[i]调整到LEFT。