1 / 45

程序设计实习

程序设计实习. 习题课 http://ai.pku.edu.cn/cpp2010. 习题课. 2951 浮点数高精度求幂 2775 文件结构图 2787 算 24. 2951. 题目描述:有一个实数 R ( 0.0 < R < 99.999 ) , 要求写程序精确计算 R 的 n 次方。 n 是整数并且 0 < n <= 25 。 输入:输入包括多组 R 和 n 。 R 的值占第 1 到 第 6 列 , n 的值占第 8 和第 9 列。

Download Presentation

程序设计实习

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 程序设计实习 习题课 http://ai.pku.edu.cn/cpp2010

  2. 习题课 2951 浮点数高精度求幂 2775 文件结构图 2787 算24

  3. 2951 题目描述:有一个实数 R ( 0.0 < R < 99.999 ) ,要求写程序精确计算 R 的 n 次方。n 是整数并且 0 < n <= 25。 输入:输入包括多组 R 和 n。 R 的值占第 1 到 第 6 列, n 的值占第 8 和第 9 列。 输出:对于每组输入,要求输出一行,该行包含精确的 R 的 n 次方。输出需要去掉前导的 0 后后面不不要的 0 。如果输出是整数,不要输出小数点。

  4. 2951 95.123 12 0.4321 20 5.1234 15 6.7592 9 98.999 10 1.0100 12 548815620517731830194541.899025343415715973535967221869852721 .00000005148554641076956121994511276767154838481760200726351203835429763013462401 43992025569.928573701266488041146654993318703707511666295476720493953024 29448126.764121021618164430206909037173276672 90429072743629540498.107596019456651774561044010001 1.126825030131969720661201

  5. 2951 思路:以95.123 12为例 • 求出小数部分长度 – 3位 • 去掉小数点,变成整数95.123 -> 95123 • 求95123^12 = 548815620517731830194541899025343415715973535967221869852721 • 重新点小数点548815620517731830194541.899025343415715973535967221869852721

  6. 2951 代码 #include<stdio.h> #include<string.h> const int MAX=100; char s[7]; int a[MAX],e,p,b,be,en,i; void mul() { int i,w=0; for(i=0;i<MAX;i++) { a[i]=a[i]*b+w; w=a[i]/10; a[i]=a[i]-w*10; } }

  7. int main() { while (scanf("%s %d",s,&e)!=EOF) { memset(a,0,sizeof(a)); b=0; //Step 1 and Step 2 for(i=0;i<strlen(s);i++) if (s[i]=='.') p=strlen(s)-i-1; else b=b*10+s[i]-'0'; a[0]=1; //Step 3 for(i=0;i<e;i++) mul(); p*=e; //Step 4 for (be=MAX-1;a[be]==0&&be>=p-1;be--); for (en=0;a[en]==0&&en<p;en++); for (i=be;i>=p;i--) printf("%d",a[i]); if (en<p) printf("."); for (i=p-1;i>=en;i--) printf("%d",a[i]); printf("\n"); } return 0; }

  8. 2775 文件结构图 DATA SET 1: ROOT | dir3 | | dir2 | | file1 | | file2 | dir1 file1 file2 file3 file4 DATA SET 2: ROOT file1 file2 file1 file2 dir3 dir2 file1 file2 ] ] file4 dir1 ] file3 * file2 file1 * #

  9. 2775 关键:用什么样数据结构存储“文件结构图” struct DIR { char name[20]; int nf; int parent; char* files[MAXF]; bool children[MAXD]; } dirs[MAXD];

  10. 2775 思路: 1.读入数据,生成dirs[ ] 2.遍历dirs[ ],输出结果 技术问题: 一个文件或者目录的父(上层)目录一定是最近的没有被”]”闭合的目录

  11. #include <iostream> #include <cstdio> #include <cstring> using namespace std; #define MAXD 200 #define MAXF 200 struct DIR { char name[20]; int nf; int parent; char* files[MAXF]; bool children[MAXD]; } dirs[MAXD]; int current = 0; int parent = 0; int data_set = 1; void new_dir(int x, char* tmp, int p) { sprintf(dirs[x].name, "%s", tmp); dirs[x].nf = 0; dirs[x].parent = p; memset(dirs[x].children, false, sizeof(dirs[x].children)); }

  12. void clear() { current = 1; parent = 0; new_dir(0, "ROOT", -1); } void insert_file(int parent, char* tmp) { dirs[parent].files[dirs[parent].nf] = new char[20]; strcpy(dirs[parent].files[dirs[parent].nf], tmp); dirs[parent].nf++; } void format_print(int dep, char* s) { for(int i = 0; i < dep; i++) printf("| "); printf("%s\n", s); } int mycompare(const void *e1, const void *e2){ return strcmp(*(char **)e1,*(char **)e2); }

  13. void work(int x, int dep) { if(x == 0) { printf("DATA SET %d:\n", data_set); } format_print(dep, dirs[x].name); for(int i = 0; i < MAXD; i++) if(dirs[x].children[i]) { work(i, dep+1); } qsort(dirs[x].files, dirs[x].nf, sizeof(dirs[x].files[0]), mycompare); for(int i = 0; i < dirs[x].nf; i++) format_print(dep, dirs[x].files[i]); }

  14. int main() { clear(); //parent=0; current = 1; while(true) { char tmp[20]; scanf("%s", tmp); if(tmp[0] == '#') break; if(tmp[0] == '*') { work(0, 0); printf("\n"); clear(); data_set++; } if(tmp[0] == 'f') { insert_file(parent, tmp); } if(tmp[0] == 'd') { new_dir(current, tmp, parent); dirs[parent].children[current] = true; parent = current; current++; } if(tmp[0] == ']') { parent = dirs[parent].parent; } } return 0; }

  15. 2787 算24 输入: 5 5 5 1 1 1 4 2 0 0 0 0 输出: YES NO

  16. 2787 算24 子问题:k个数算24 递归:从k个数算24,规约到k-1个数算24 方法:从k个数中选2个数a和b,及一种运算op;将a和b从k个数中删除,再将(a op b)加入

  17. #include<iostream> #include<cmath> using namespace std; bool right; double ele[4]; int main() { while(cin>>ele[0]>>ele[1]>>ele[2]>>ele[3]) { if(ele[0]==0||ele[1]==0||ele[2]==0||ele[3]==0) break; else if(cal(4)==1) cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 0; }

  18. bool cal(int count) { int i,j; double temp1,temp2; if(count==1) if(ele[0]<24.001&&ele[0]>23.999) return true; else return false; for(i=0;i<count-1;i++) { for(j=i+1;j<count;j++){ temp1=ele[i]; temp2=ele[j]; ele[i]=temp1+temp2; ele[j]=ele[count-1]; if(cal(count-1)) return true; ele[i]=temp1-temp2; if(cal(count-1)) return true;

  19. ele[i]=temp2-temp1; if(cal(count-1)) return true; ele[i]=temp1*temp2; if(cal(count-1)) return true; if(temp2!=0) { ele[i]=temp1/temp2; if(cal(count-1)) return true; } if(temp1!=0) { ele[i]=temp2/temp1; if(cal(count-1)) return true; } ele[i]=temp1; ele[j]=temp2; } } return false; }

  20. 2791 矩形覆盖 1833 排列 2950 摘花生 1095 Trees Made to Order 2766 最大子矩阵

  21. 2791 矩形覆盖 题目描述: 在平面上给出了n个点,现在需要用一些平行于坐标轴的矩形把这些点覆盖住。每个点都需要被覆盖,而且可以被覆盖多次。每个矩形都至少要覆盖两个点,而且处于矩形边界上的点也算作被矩形覆盖。注意:矩形的长宽都必须是正整数,也就是说矩形不能退化为线段或者点。 现在的问题是:怎样选择矩形,才能够使矩形的总面积最小。 输入: 输入包括多组测试数据。每组测试数据的第一行给出n (2 <= n <= 15),表示平面上的点数。后面的n行,每行上包括两个整数x, y (-1000 <= x, y <= 1000),给出一个点在平面上的x坐标和y坐标。输入数据保证:这n个点在平面上的位置各不相同。 最后一组测试数据中n = 0,表示输入的结束,这组数据不用处理。 输出: 对每一组测试数据,输出一行,包括一个正整数,给出矩形的最小总面积。

  22. 2791 样例输入: 2 0 1 1 0 0 样例输出: 1

  23. 2791 子问题:对于点集P, 求出覆盖P所用的矩形的最小面积和 - least(P) 规约:least(P) = min{least(Q) + least(R), S(P)} 其中Q∪R = P, S(P)为用一个矩形覆盖P的最小面积 问题规模:P的所有子集数目,2^|P|

  24. 2791 - TLE 能否缩减枚举空间,同时保证不漏掉最优解? 定义:如果对于点集P, least(P)==S(P), 则称P是紧密的。即如果覆盖点集P的最优方案是用一个矩形去覆盖,则P是紧密的。 Q和R中至少有一个是紧密的

  25. 2791 - TLE 对于确定的P,如何找到所有的(Q, R)使得Q是紧密的,且Q∪R = P ? 不好确定…换个思路: 对于确定的一个紧密的Q,枚举所有的R,用least(Q)+least(P)更新least(Q ∪ R)

  26. 2791 – 状态表示 对于n个点的点集P,用n位2进制数来表示P的所有子集。 例如P={p2, p1, p0},用 1=(001)2表示{p0}, 2=(010)2表示{p1}, 3=(011)2表示{p1, p0} 7=(111)2表示{p2, p1, p0} least(P) = least(7)

  27. #include<stdio.h> int x[15], y[15]; int area[1<<15]; int least[1<<15]; int m; int main() { int num,i,j,xs,ys,xl,yl,size,a,b; while(1) { scanf("%d", &num); if(!num) break; for( i=0 ; i<num ; i++ ) scanf("%d%d", x+i, y+i); size = (1<<num) ; for( i=1 ; i<size ; i++ ) least[i] = 2000 * 2000 ; least[0]=0;

  28. for( i=1 ; i<size ; i++ ) { xs=ys=1000; xl=yl=-1000; for( j=0 ; j<num ; j++ ) if( (i>>j)&1 ) { if( x[j]>xl ) xl=x[j]; if( x[j]<xs ) xs=x[j]; if( y[j]>yl ) yl=y[j]; if( y[j]<ys ) ys=y[j]; } a=xl-xs; b=yl-ys; if(a==0) a=1; if(b==0) b=1; area[i]=a*b; } area[0]=least[0]=0;

  29. for(i = 1; i < size; i++) if(i & (i - 1)) least[i] = area[i]; for(i = 1; i < size; i++) if(least[i] == area[i]) { for(int j = 1; j < size; j++) if(least[i | j] > least[i] + least[j]) least[i | j] = least[i] + least[j]; } printf("%d\n", least[size-1]); } return 0; }

  30. 1833 – 排列 题目描述 大家知道,给出正整数n,则1到n这n个数可以构成n!种排列,把这些排列按照从小到大的顺序(字典顺序)列出,如n=3时,列出1 2 3,1 3 2,2 1 3,2 3 1,3 1 2,3 2 1六个排列。 给出某个排列,求出这个排列的下k个排列,如果遇到最后一个排列,则下1排列为第1个排列,即排列1 2 3…n。 比如:n = 3,k=2 给出排列2 3 1,则它的下1个排列为3 1 2,下2个排列为3 2 1,因此答案为3 2 1。 输入 第一行是一个正整数m,表示测试数据的个数,下面是m组测试数据,每组测试数据第一行是2个正整数n( 1 <= n < 1024 )和k(1<=k<=64),第二行有n个正整数,是1,2 … n的一个排列。 输出 对于每组输入数据,输出一行,n个数,中间用空格隔开,表示输入排列的下k个排列。

  31. 1833 – 排列 样例输入 3 3 1 2 3 1 3 1 3 2 1 10 2 1 2 3 4 5 6 7 8 9 10 样例输出 3 1 2 1 2 3 1 2 3 4 5 6 7 9 8 10

  32. 1833 思路 while(k--) next_permutation(); 1.从右向左找到第一个下降的元素a[i],如果没有sort(a[1]…a[n]) 2.从a[i+1]…a[n]中找到最小的比a[i]大的元素a[j] 3.swap(a[i], a[j]) 4.sort(a[i+1]…a[j])

  33. 2950 摘花生 为了训练多多的算术,鲁宾逊先生说:“你先找出花生最多的植株,去采摘它的花生;然后再找出剩下的植株里花生最多的,去采摘它的花生;依此类推,不过你一定要在我限定的时间内回到路边。”

  34. 2950 摘花生 路径唯一,只需判断:如果超过限定时间跳出 为什么AC的人那么少?

  35. 1095 – Trees Made to Order The empty tree is numbered 0.The single-node tree is numbered 1.All binary trees having m nodes have numbers less than all those having m+1 nodes.Any binary tree having m nodes with left and right subtrees L and R is numbered n such that all trees having m nodes numbered > n have either Left subtrees numbered higher than L, or A left subtree = L and a right subtree numbered higher than R.

  36. 样例输入 1 20 31117532 0 样例输出 X ((X)X(X))X (X(X(((X(X))X(X))X(X))))X(((X((X)X((X)X)))X)X)

  37. 1095 子问题:输出编号为k的二叉树 归约:对于编号为k的二叉树,如何求出它的左子树编号l以及右子树编号r? 如果可以求出l及r: ( 输出l)X(输出r) 为了叙述方便,用a(n)表示包含n个节点的二叉树的数目 a(0)=1 a(n)=a(0)*a(n-1)+a(1)*a(n-2)+…+a(i)*a(n-i-1)+…+a(n-1)*a(0) 太复杂了!

  38. 1095 另一种子问题表示 子问题:输出在所有节点数为n的二叉树中,编号为m的二叉树T(n,m) 对于输入的k,如何求出对应的n,m? 归约:对于T(n,m),如何求出左子树T(ln,lm)及右子树T(rn,rm) n=最小的n0,使a(0)+a(1)+a(2)…+a(n0) >= k m = k-a(0)-a(1)-a(2)-…-a(n-1)-1, 从0开始编号

  39. 1095 对于T(n,m),如何求出左子树T(ln,lm)及右子树T(rn,rm)? a(0)*a(n-1)+a(1)*a(n-2)+…a(i)*a(n-i-1) >= m+1 ln = i lm = [m-a(0)*a(n-1)-a(1)*a(n-2)-…-a(i-1)*(n-i)]/a(n-i-1) rn = n-i-1 rm = [m-a(0)*a(n-1)-a(1)*a(n-2)-…-a(i-1)*(n-i)]%a(n-i-1)

  40. #include<iostream> using namespace std; long a[20],n,num; int main() { a[0]=a[1]=1; for(int i=2;i<20;i++) for(int j=0;j<i;j++) a[i]+=a[j]*a[i-j-1]; long sum; cin>>num; while(num!=0) { sum=0;n=1; while(sum<num)sum+=a[n++]; n--; go(n,num-(sum-a[n])-1); cout<<endl; cin>>num; } return 0; }

  41. void go(int n,int num) { long sum=0; for(int i=0;i<n;i++) { if(sum+a[i]*a[n-1-i]>=num+1) { if(i!=0) { cout<<'('; go(i,(num-sum)/a[n-1-i]); cout<<')'; } cout<<'X'; if(n-1-i!=0) { cout<<'('; go(n-1-i,(num-sum)%a[n-1-i]); cout<<')'; } break; } sum+=a[i]*a[n-1-i]; } }

  42. 2766 最大子矩阵 已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵。比如,如下4 * 4的矩阵0 -2 -7 09 2 -6 2-4 1 -4 1-1 8 0 -2的最大子矩阵是9 2-4 1-1 8这个子矩阵的大小是15

  43. 2766 一维问题:对于数列X1, X2, X3 … Xn 求出和最大的自区间 子问题:以Xi结尾的区间的最大和f(i) f(i) = max{f(i-1) + Xi, Xi} DP求解

  44. 2766 二维问题: 枚举矩形的左右边界,转变为一维问题 边界[i, r] X1 = a[1][i]+…+a[1][r] X2 = a[2][i]+…+a[2][r] …… Xn = a[n][i]+…+a[n][r] 于是:求X1, X2, … , Xn的最大子区间和

  45. 2766 利用部分和优化 a[k][i]+…+a[k][j] = sum[k][j] – sum[k][i-1]

More Related