收藏 分享(赏)

NOIP初赛试题分类汇总_完善程序部分.doc

上传人:HR专家 文档编号:11441684 上传时间:2020-04-28 格式:DOC 页数:20 大小:555.50KB
下载 相关 举报
NOIP初赛试题分类汇总_完善程序部分.doc_第1页
第1页 / 共20页
NOIP初赛试题分类汇总_完善程序部分.doc_第2页
第2页 / 共20页
NOIP初赛试题分类汇总_完善程序部分.doc_第3页
第3页 / 共20页
NOIP初赛试题分类汇总_完善程序部分.doc_第4页
第4页 / 共20页
NOIP初赛试题分类汇总_完善程序部分.doc_第5页
第5页 / 共20页
点击查看更多>>
资源描述

1、NOIP初赛试题汇总完善程序20041Joseph题目描述:原始的Joseph问题的描述如下:有n个人围坐在一个圆桌周围,把这n个人依次编号为1,n。从编号是1的人开始报数,数到第m个人出列,然后从出列的下一个人重新开始报数,数到第m个人又出列,如此反复直到所有的人全部出列为止。比如当n=6,m=5的时候,出列的顺序依次是5,4,6,2,3,1。现在的问题是:假设有k个好人和k个坏人。好人的编号的1到k,坏人的编号是k+1到2k。我们希望求出m的最小值,使得最先出列的k个人都是坏人。输入:仅有的一个数字是k(0 k 14)。输出:使得最先出列的k个人都是坏人的m的最小值。输入样例:4输出样例:

2、30程序:#include long k, m, begin;int check(long remain)long result = ( ) % remain;if ( )begin = result; return 1;else return 0;int main()long i, find = 0;scanf(%ld, &k);for (m = k; ; m+)find = 1; begin = 0;for (i = 0; i k; i+)if (!check( )find = 0; break;printf(%ldn, );return 0;2逻辑游戏题目描述:一个同学给了我一个逻辑游戏

3、。他给了我图1,在这个图上,每一段边界都已经进行了编号。我的任务是在图中画一条连续的曲线,使得这条曲线穿过每一个边界一次且仅穿过一次,而且曲线的起点和终点都在这整个区域的外面。这条曲线是容许自交的。对于图1,我的同学告诉我画出这样的一条曲线(图2)是不可能的,但是对于有的图形(比如图3),画出这样一条曲线是可行的。对于给定的一个图,我想知道是否可以画出满足要求的曲线。图1图2图3图4输入:输入的图形用一个nn的矩阵表示的。矩阵的每一个单元里有一个0到255之间(包括0和255)的整数。处于同一个区域的单元里的数相同,相邻区域的数不同(但是不相邻的区域里的数可能相同)。输入的第一行是n(0n10

4、0)。以下的n行每行包括n个整数,分别给出对应的单元里的整数(这n个整数之间用空格分开)。图4给出了输入样例对应的图形。输出:当可以画出满足题意的曲线的时候,输出“YES”;否则,输出“NO”。输入样例:31 1 21 2 21 1 2输出样例:YES程序:#include #include int orig, n, ns, a102102, bun;int d=1, 0, -1, 0, 0, 1, ;void plimba(int x, int y)int i, x1, y1;axy = -axy;if (abs(ax - 1y) != orig & ( != ax - 1y| abs(ax

5、y - 1) != orig) ns+;if (abs(ax + 1y) != orig & (ax + 1y - 1 != ax + 1y| abs(axy - 1) != orig) ns+;if (abs(axy - 1) != orig & ( != axy - 1| abs(ax - 1y) != orig) ns+;if (abs(axy + 1) != orig & (ax - 1y + 1 != axy + 1| abs(ax - 1y) != orig) ns+;for (i = 0; i = 1 & x1 = 1 & y1 = n & )plimba(x1, y1);int

6、 main()int i, j;bun = 1;scanf(%d, &n);for (i = 0; i = n+1; i+) for (j = 0; j = n+1; j+) aij = 0;a00 = -1; an + 10 = -1; a0n + 1 = -1; an + 1n + 1 = -1;for (i = 1; i = n; i+) for ( j = 1; j = n; j+) scanf(%d, &(aij);for (i = 1; i =n ; i+)for (j = 1; j -1)ns = 0; ;plimba(i, j);if (ns % 2 = 1)bun = 0;i

7、f (bun) printf(YESn); else printf(NOn);return 0;20051木材加工 题目描述: 木材厂有一些原木,现在想把这些木头切割成一些长度相同的小段木头(木头有可能有剩余),需要得到的小段的数目是给定了的。当然,我们希望得到的小段越长越好,你的任务是计算能够得到的小段木头的最大长度。 木头长度的单位是 cm。原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。 输入: 第一行是两个正整数N和K(1 N 10000,1 K 10000),N是原木的数目,K是需要得到的小段的数目。 接下来的N行,每行有一个1到10000之间的正整数,表示一根原木

8、的长度。 输出: 输出能够切割得到的小段的最大长度。如果连1cm长的小段都切不出来,输出”0”。 输入样例: 3 7 232 124 456 输出样例: 114 程序: #include int n, k, len10000; int isok(int t) int num = 0, i; for (i = 0; i = k) break; num = ; if ( ) return 1; else return 0; int main() int i, left, right, mid; scanf(%d%d, &n, &k); right = 0; for (i = 0; i n; i+)

9、 scanf(%d, &(leni); if (right leni) right = leni; right+; ; while ( right) mid = (left + right) / 2; if ( ) right = mid; else left = mid; printf (%dn, left); return 0; 2N叉树 题目描述: 我们都了解二叉树的先根遍历,中根遍历和后根遍历。当知道先根遍历的结果和中根遍历结果的时候,我们可以唯一的确定二叉树;同样的,如果知道了后根遍历的结果和中根遍历结果,二叉树也是唯一确定的。但是如果只知道先根遍历和后根遍历的结果,二叉树就不是唯一

10、的了。 但是我们可以计算满足条件的不同二叉树的一共有多少个。这不是一个很困难的问题,稍微复杂一点,我们把这个问题推广到 N叉树。 我们用小写英文字母来表示 N 叉树的结点,不同的结点用不同的字母表示。比如,对于4叉树,如果先根遍历的结果是abdefgc,后根遍历的结果是 defgbca,那么我们可以得到6个不同的4叉树(如下图)。 输入: 输入数据包括3行。 第一行是一个正整数N(1 N 20),表示我们要考虑N叉树。 第二行和第三行分别是两个字符串序列,分别表示先根遍历和后根遍历的结果。 输出: 输出不同的N叉树的数目。题目中给的数据保证得到的结果小于231。 输入样例: 4 abdefgc

11、 defgbca 输出样例: 6 程序: #include #include char str1100, str2100; int N; long com100100; long getcom(int x, int y) if (y = 0 | x = y) ; else if (comxy != 0) return comxy; else comxy = getcom(x - 1, y)+ ; return comxy; long count(int a, int b, int c) long sum = 1; int k = 0; int s = a + 1, t = c, p; if (

12、a = b) return 1; while(s = b) p = t; while(str1s != str2t) t+; sum = sum * count(s, s + t - p, p); s = ; ; k+; return * getcom(N, k); int main() int len; scanf(%d, &N); scanf(%s%s, str1, str2); len = strlen(str1); printf(%ldn, count( ); return 0; 20061 (选排列)下面程序的功能是利用递归方法生成从1到n(n10)的n个数中取k(1=k=n)个数的

13、全部可能的排列(不一定按升序输出)。例如,当n=3,k=2时,应该输出(每行输出5个排列) : 12 13 21 23 32 31 程序: #include int n,k,a10; long count=0; void perm2(int j) int i,p,t; if( ) for(i=k;i=n;i+) count+; t=ak; ak=ai; ai=t; for( ) printf(%1d,ap); /* %1d中是数字1,不是字母l */ printf( ); t=ak;ak=ai;ai=t; if(count%5=0) printf(n); return; for(i=j;i=n

14、;i+) t=aj;aj=ai;ai=t; ; t=aj; ; main() int i; printf(nEntry n,k (k=n):n); scanf(%d%d,&n,&k); for(i=1;i4-2-1-5-3。遗传算法的核心是通过两个个体的交叉操作,产生两个新的个体。下面的程序给出了最简单的一种交叉算法。具体过程如下: (1)选定中间一段作为互换段,该段的起止下标为t1,t2,随机生成t1,t2后,互换两段。 (2)互换后,在每个新的排列中可能有重复数字,因而不能作为新个体的编码,一般再做两步处理:(2.1) 将两个互换段中,共同的数字标记为0,表示已处理完。 (2.2) 将两个

15、互换段中其余数字标记为1,按顺序将互换段外重复的数字进行替换。 例如:n=12,两个个体分别是: a1: 1 3 5 4 * 2 6 7 9 * 10 12 8 11 a2: 3 2 1 12 * 6 7 10 11 * 8 5 4 9 t1=5,t2=8。上述每一行中,两个星号间的部分为互换段。假定数组的下标从1开始,互换后有: a1: 1 3 5 4 * 6 7 10 11 * 10 12 8 11 a2: 3 2 1 12 * 2 6 7 9 * 8 5 4 9 然后,将数字6,7对应的项标记为0,星号内数字2,9,10,11对应的项标记为1,并且按顺序对应关系为: 102 , 119。

16、 于是, 将a19=10替换为a19=2,将a22=2替换为a22=10,类似再做第2组替换。这样处理后,就得到了两个新个体: a1: 1 3 5 4 6 7 10 11 2 12 8 9 a2: 3 10 1 12 2 6 7 9 8 5 4 11 (3) 输出两个新个体的编码。 (4)程序: #include #include #define N 20 int a1N,a2N,kz1N,kz2N,n; int rand1(int k) int t=0; while(tk) t=(int)(double)rand()/RAND_MAX*k); return t; void read1(int

17、 a,int m) 读入数组元素a1至am,a0=0,略。 void wrt1(int a,int m) 输出数组元素a1至am,略。 void cross(int a1, int a2,int t1, int t2, int n) int i,j,k,t,kj; for(i=t1; i=t2; i+) t=a1i; ; for(i=1;i=n;i+) if(it2) kz1i=kz2i=-1; else ; for(i=t1;i=t2;i+) for(j=t1;j=t2;j+) if(a1i=a2j) ; break; for(i=t1;i=t2;i+) if(kz1i=1) for(j=t

18、1;j=t2;j+) if(kz2j=1) kj=j; break; for(j=1;j=n;j+) if( ) a1j=a2kj;break; for(j=1;j5):n); scanf(%d,&n); printf(input array 1 (%dnumbers):n,n); read1(a1,n); printf(input array 2 (%dnumbers):n,n); read1(a2,n); t1=rand1(n-1); do t2=rand1(n-1); while(t1=t2); if(t1t2) k=t1; t1=t2; t2=k; wrt1(a1,n); wrt1(a

19、2,n); 20071(格雷码,Gray Code) 格雷码是对十进制数的一种二进制编码。编码顺序与相应的十进制数的大小不一致。其特点是:对于 两个相邻的十进制数,对应的两个格雷码只有一个二进制位不同。另外,最大数与最小数之间也仅有一个二进制位不同,以4 位二进制数为例,编码如下: 十进制数格雷码十进制数格雷码 0 0000 8 1100 1 0001 9 1101 2 0011 10 1111 3 0010 11 1110 4 0110 12 1010 5 0111 13 1011 6 0101 14 1001 7 0100 15 1000 如果把每个二进制的位看作一个开关,则将一个数变为相

20、邻的另一个数,只须改动一个开关。因此, 格雷码广泛用于信号处理、数-模转换等领域。 下面程序的任务是:由键盘输入二进制数的位数n (n16),再输入一个十进制数m(0m2n),然 后输出对应于m 的格雷码(共n 位,用数组gr存放)。 为了将程序补充完整,你必须认真分析上表的规律,特别是对格雷码固定的某一位,从哪个十进制数起,由0 变为1,或由1 变为0。 #include main() int bound=1,m,n,i,j,b,p,gr15; printf(input n,mn); scanf(%d%d,&n,&m); for(i=1;i=n;i+) bound= ; if(m=bound

21、) printf(Data error!n); ; b=1; for(i=1;i=n;i+) p=0; b=b*2; for( ;j=m;j+) if( ) p=1-p; gri=p; for(i=n; ) printf(%1d,gri); /* 在%1d 中出现的是数字1,不是字母l */ printf(n); 2(连续邮资问题)某国发行了n 种不同面值的邮票,并规定每封信最多允许贴m 张邮票,在这 些约束下,为了能贴出1,2,3,,maxvalue连续整数集合的所有邮资,并使maxvalue 的值最 大,应该如何设计各邮票的面值?例如,当n=5、m=4 时,面值设计为1,3,11,15,3

22、2,可使 maxvalue 达到最大值70(或者说,用这些面值的1 至4 张邮票可以表示不超过70 的所有邮资,但无 法表示邮资71。而用其他面值的1 至4 张邮票如果可以表示不超过k 的所有邮资,必有k70)。 下面是用递归回溯求解连续邮资问题的程序。数组x1:n表示n 种不同的邮票面值,并约定各元 素按下标是严格递增的。数组bestx 1:n存放使maxvalue 达到最大值的邮票面值(最优解), 数组ymaxl用于记录当前已选定的邮票面值x1:i能贴出的各种邮资所需的最少邮票张数。请将程序补充完整。 #include #define NN 20 #define maxint 30000

23、#define maxl 500 /*邮资的最大值*/ int n,m,bestxNN,xNN,ymaxl,maxvalue=0; void result() 输出结果:最大值:maxvalue 及最优解: bestx1:n(略) void backtrace(int i,int r) int j,k,zmaxl; for(j=0;j= ;j+) if(yjm) for(k=1;k=m-yj;k+) if(yj+k=y ) y =yj+k; while(yrn) if(r-1maxvalue) maxvalue= ; for(j=1;j=n;j+) bestxj=xj; return; for

24、(k=0;kmaxl;k+) zk=yk; for(j= ;j=r;j+) xi=j; ; for(k=0;kmaxl;k+) yk=zk; void main() int j; printf(input n,m:n); scanf(“%d%d”,&n,&m); for(j=1;jmaxl;j+) yj=maxint; y0=0; x0=0; x1=1; backtrace(2,1); result(); 20081(找第k大的数) 给定一个长度为1,000,000的无序正整数序列,以及另一个数n(1=n=1000000),接下来以类似快速排序的方法找到序列中第n大的数(关于第n大的数:例如序

25、列1,2,3,4,5,6中第3大的数是4)。#include #include int a1000001,n,ans = -1;void swap(int *a,int *b)int c;c = *a; *a = *b;*b = c;int FindKth(int left, int right, int n)int tmp,value,i,j;if (left = right) return left;tmp = rand()% (right - left) + left;swap( &atmp, &aleft );value = i = left;j = right;while (i j)

26、while (i j & ) j -;if (i j) ai = aj; i +; else break;while (i j & ) i +;if (i j) aj = ai; j - -; else break; if (i n) return return i;int main()int i;int m = 1000000;for (i = 1;i = m;i +)scanf(%d, &ai);scanf(%d, &n);ans = FindKth(1,m,n);printf(%dn, aans); return 0;2(矩阵中的数字)有一个n*n(1=n=5000)的矩阵a, 对于1=

27、i n,1=j=n, ai,j ai + 1,j aj,i aj,i+1。即矩阵中左右相邻的两个元素,右边的元素一定比左边的大。上下相邻的两个元素,下面的元素一定比上面的大。给定矩阵a中的一个数字k,找出k所在的行列(注意:输入数据保证矩阵中的数各不相同)。#include int n,k,answerx,answery;int a50015001;void FindKPosition()int i = n,j = n;while (j 0)if (anj 1) i -;while ( & j = n) j +; int main()int i,j;scanf( %d, &n );for (i

28、 = 1;i = n;i +)for (j = 1;j = n;j +)scanf( %d, &aij);scanf( %d, &k );FindKPosition();printf(%d %dn, answerx, answery);return 0;20091(最大连续子段和)给出一个数列(元素个数不多于100),数列元素均为负整数、正整数、0。请找出数列中的一个连续子数列,使得这个子数列中包含的所有元素之和最大,在和最大的前提下还要求该子数列包含的元素个数最多,并输出这个最大和以及该连续子数列中元素的个数。例如数列为4,-5,3,2,4时,输出9和3;数列为1 2 3 -5 0 7 8时

29、,输出16和7。#include int a101;int n,i,ans,len,tmp,beg,end;int main()scanf(%d,&n);for (i=1;i=n;i+)scanf(%d,&ai);tmp=0;ans=0;len=0;beg= ;for (i=1;ians)ans=tmp+ai;len=i-beg;else if ( &i-beglen)len=i-beg;if (tmp+ai )beg= ;tmp=0;else ;printf(%d %dn,ans,len);return 0;2. (寻找等差数列) 有一些长度相等的等差数列(数列中每个数都为059的整数),设

30、长度均为L,将等差数列中的所有数打乱顺序放在一起。现在给你这些打乱后的数,问原先,L最大可能为多大?先读入一个数n(1=n=60),再读入n个数,代表打乱后的数。输出等差数列最大可能长度L。#include int hash60;int n, x, ans, maxnum;int work(int now) int first, second, delta, i;int ok;while ( & !hashnow)+now;if (now maxnum)return 1;first = now;for (second = first; second maxnum) break;if (delt

31、a = 0)ok = ( ); elseok = 1;for (i = 0; i ans; i+)ok = & (hashfirst+delta*i); if (ok)for (i = 0; i ans; i+)hashfirst+delta*i-;if (work(first) return 1;for (i = 0; i ans; i+)hashfirst+delta*i+;return 0;int main()int i;memset(hash, 0, sizeof(hash);scanf(%d, &n);maxnum = 0;for (i = 0; i maxnum)maxnum =

32、x;for (ans = n; ans = 1; ans-)if ( n%ans=0 & ) printf(%dn, ans);break;return 0;20101.(过河问题)在一个月黑风高的夜晚,有一群人在河的右岸,想通过唯一的一根独木桥走到河的左岸。在这伸手不见五指的黑夜里,过桥时必须借助灯光来照明,不幸的是,他们只有一盏灯。另外,独木桥上最多承受两个人同时经过,否则将会坍塌。每个人单独过桥都需要一定的时间,不同的人需要的时间可能不同。两个人一起过桥时,由于只有一盏灯,所以需要的时间是较慢的那个人单独过桥时所花的时间。现输入n(2n100)和这n个人单独过桥时需要的时间,请计算总共最

33、少需要多少时间,他们才能全部到达河的左岸。例如,有3个人甲、乙、丙,他们单独过桥的时间分别为1、2、4,则总共最少需要的时间为7。具体方法是:甲、乙一起过桥到河的左岸,甲单独回到河的右岸将灯带回,然后甲、丙再一起过桥到河的左岸,总时间为2+1+4=7。#include #define SIZE 100#define INFINITY 10000#define LEFT 1#define RIGHT 0#define LEFT_TO_RIGHT 1#define RIGHT_TO_LEFT 0int n,timeSIZE,posSIZE;int max(int a,int b) if(ab) r

34、eturn a; else return b;int go(int stage) int i,j,num,tmp,ans; if(stage=RIGHT_TO_LEFT) num=0; ans=0; for(i=1;ians) ans=timei; if( ) return ans; ans=INFINITY; for(i=1;i=n-1;i+) if(posi=RIGHT) for(j=i+1;j=n;j+) if(posj=RIGHT) posi=LEFT; posj=LEFT; tmp=max(timei,timej)+ ; if(tmpans) ans=tmp; posi=RIGHT; posj=RIGHT; return ans; if(stage=LEFT_TO_RIGHT) ans=INFINITY; for(i=1;i=n;i+) if( ) posi=RIGHT;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 网络科技 > 计算机原理

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报