1 / 32

2.1数字矩阵(mat)

数组和函数题目讲解二 --陈静 031002402. 2.1数字矩阵(mat). 问题描述: 输出一个n 层的正方形数字矩阵。最外层是第一层数字为1,从外到内各层的数字依次对应1,2..,n,要求同一层的数字相同. 2.1数字矩阵(mat). 解题思路: 矩阵的形成:矩阵是一层层的形成方式,且每一层的数字是相同的! 解决方案:那我们也一层层地模拟矩阵的形成过程吧!. 2.1数字矩阵(mat).

beyla
Télécharger la présentation

2.1数字矩阵(mat)

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. 数组和函数题目讲解二 --陈静 031002402

  2. 2.1数字矩阵(mat) • 问题描述: • 输出一个n 层的正方形数字矩阵。最外层是第一层数字为1,从外到内各层的数字依次对应1,2..,n,要求同一层的数字相同

  3. 2.1数字矩阵(mat) • 解题思路: • 矩阵的形成:矩阵是一层层的形成方式,且每一层的数字是相同的! • 解决方案:那我们也一层层地模拟矩阵的形成过程吧!

  4. 2.1数字矩阵(mat) • 具体过程: • 矩阵有n层,每一层的形成过程是类似的,所以可以用一个循环语句,循环n次 • 一层层又是怎么模拟的呢? • 1.每一层是由上下2行和左右2列构成的。 • 2.每一行和每一列单独来看数字的个数是一样的, • 个数=2*n-1。 • 3.再观察第x(1=<x<=n)层的2行横坐标分别x和2*n-x,纵坐标的范围是(x,2*n-x),2列的纵坐标分别x和2*n-x,横坐标的范围是(x,2*n-x)。(这时发现可以用一个循环把2行2列给模拟出来)

  5. 2.1数字矩阵(mat) • 主要代码: • void mat(int n,int num[25][25])//模拟数字矩阵形成的函数 • { • int i,j,k,s; • s=2*n-1; • for(i=1;i<=n;i++)//n层 • { • for(j=i;j<=s-i+1;j++)//每一层的形成过程 • { • num[i][j]=i;//上边界 • num[s-i+1][j]=i;//上边界 • num[j][i]=i;//左边界 • num[j][s-i+1]=i;//右边界 • } • } • }

  6. 2.2寻找Key word(find) • 问题描述: •   给定N个数,要求从这N个数中拿出两个数,若这两个数的和与这两个数的差的绝对值皆为素数,称这一对数为Key word,并计数。要你计算出一共有多少对这样的数。

  7. 2.2寻找Key word(find) • 解题思路: • 1.首先我们要知道怎么判断一个数是否是素数!这时我们可以写一个函数实现该功能! • 2.我们要在这n个数中找出所有可能的不重复的2个数的组合,进而判断组合中2数的和与差的绝对值是否是素数!

  8. 2.2寻找Key word(find) • 具体过程: • 素数的判定: • 1. 0,1不是素数 • 2.对于大于1的数,就判断是否有除了1和自身之外的因子。 • for (i=2;i<=sqrt(x);i++)if (x%i==0) ..(不是素数) • 任取2个数的组合总共有(n*n-1)/2种 • 用2重循环实现 • for (i=0;i<n-1;i++) • for (j=i+1;j<n;j++) • {......}

  9. 主要代码: int isPrime(int x)//素数函数 { int i; if ((x==0)||(x==1)) return 0; for (i=2;i<=sqrt(x);i++) if (x%i==0) return 0; return 1; } for (i=0;i<n;i++) scanf("%d",&a[i]); count=0; for (i=0;i<n-1;i++) for (j=i+1;j<n;j++) {if(isPrime(a[i]+a[j]) &&isPrime(abs(a[i]-a[j]))) count++;} printf("%d\n",count); 2.2寻找Key word(find)

  10. 2.3 讨厌的ACM(acm) • 问题描述: • 一本只包含三个字母,A,C,M的书,这三个字母,而且排列毫无规律可言。希望你能将这些字母中含有“ACM”这个子串删除,删除后组成的新字母若还有包含,继续不断的删除,看最后剩下的字符串是什么? • 示例:输入:AAACMCM,输出:A

  11. 2.3 讨厌的ACM(acm) • 解题思路: • 1.每一次从字符串的第一个字符开始寻找是否有连续的ACM出现 • 2.若找到了,就删除该子串。怎么删除?把要删除子串后面的字符串往前移3个位置,然后返回步骤1,如果找不到就按顺序往后找。如果找完一遍都没找到就跳出循环输出最后的字符串

  12. 2.3 讨厌的ACM(acm) • 具体过程: • 寻找一遍是如何寻找的? • for (i=0;i<len-2;i++) • if (st[i]=='A'&&st[i+1]=='C'&&st[i+2]=='M') • {......} • 注意下标是从0开始到len-3,若是到len-1,st[i+1],st[i+2]就会超出目前字符串的范围 • 找到后如何删除? • for (j=i;j<len-2;j++) • st[j]=st[j+3];

  13. 代码示例: #include<stdio.h> #include<math.h> #include<string.h> char st[1000]; int flag; void delete_st() { int i,j,find=0,len=strlen(st); for (i=0;i<len-2;i++) if (st[i]=='A'&&st[i+1]=='C'&&st[i+2]=='M') {find=1;break; } if (find) { flag=1; for (j=i;j<len-2;j++) st[j]=st[j+3]; }} int main() { scanf("%s",st); flag=1; while (flag) { flag=0; delete_st(); } printf("%s\n",st); return 0; } 2.3 讨厌的ACM(acm)

  14. 2.4zoj问题(zoj) • 问题描述: •   对给定的字符串(只包含'z','o','j'三种字符),判断他是否能AC。 • 是否AC的规则如下: • 1. zoj能AC; • 2. 若字符串形式为xzojx,则也能AC,其中x可以是N个'o' 或者为空; • 3. 若azbjc 能AC,则azbojac也能AC,其中a,b,c为N个'o'或者为空;

  15. 2.4zoj问题(zoj) • 解题思路: • 1. 3种能AC的字符串都有一个共同的特点:只有1个z, • 和1个j,且z在j前 • 2.在符合了以上的条件后,我们再分别判断是否符合3种情况的一个。 • (1)第一个和第二个条件可以直接判断也可归为一类就是xzojx,此时z前面o的个数和j后面o的个数是一样的且z,j之间只有一个o。

  16. 2.4zoj问题(zoj) • (2)第3种情况包含一种递归的概念。 • 要判断azboojaac是否可以AC就看azbojac是否可以AC, • 以此类推,一直递归到z,j之间的o只剩一个时或无法递归时,再判断是否符合第一种和第二种的情况,符合则说明azboojaac可以AC,不然就不能。 • 实现比较复杂,具体实现参见代码

  17. 2.4zoj问题(zoj) • 代码示例 • #include<stdio.h> • #include<string.h> • int isok(int x,int y,int z) • { • if (x<0||y<0||z<0) return 0; • if (x==0 && y==1 && z==0) return 1; //zoj的情况 • if (x==z && y==1) return 1; //xzojx的情况 • if (isok(x,y-1,z-x)) return 1; //第3种情况 • return 0; • } • int main() • { • int T,len,numj,numz,num1,num2,num3,i; • char st[1001]; • scanf("%d",&T);

  18. 2.4zoj问题(zoj) • while (T--) • { • scanf("%s",st); • len=strlen(st); • numz=numj=0; • for (i=0;i<len;i++) • if (st[i]=='z') numz++; //算z的个数 • else • if (st[i]=='j') numj++; //算j的个数 • if (numj!=1&&numz!=1) {printf("Wrong Answer\n"); continue;} • numz=numj=0; • for (i=0;i<len;i++) • if (st[i]=='z') numz=i; • else • if (st[i]=='j') numj=i; • if (numz>numj) {printf("Wrong Answer\n"); continue;//判断z是否在j之前

  19. 2.4zoj问题(zoj) • num1=num2=0; • for (i=0;i<len;i++) • if (st[i]=='z') break; • else if (st[i]=='o') num1++; //算z之前有多少个'o' • for (i=num1+1;i<len;i++) • if (st[i]=='j') break; • else if (st[i]=='o') num2++; //算z,j之间有多少个'o' • num3=len-(num1+num2+2); //算j之后有多少个'o' • if (isok(num1,num2,num3)) printf("Accepted\n"); • else printf("Wrong Answer\n"); • } • return 0; • }

  20. 2.5再见括号君(Bracket_again) 问题描述: 给出序列,每个数字代表每个“)”前有多少个“(” 输出序列,每个数字代表每个“)”与从其自身往前数第几个“(”匹配 题目保证能匹配(之前数据错了::>A<:: 解题思路: 根据序列模拟出原字符串 根据模拟后的字符串匹配输出

  21. 2.5再见括号君(Bracket_again) • 模拟 char s[N<<1];//模拟串数组 int p[N];//读入序列数组 int top=0; for(i=1;i<n;++i) { for(j=0;j<p[j]-p[j-1];++j) s[top++]='('; s[top++]=')'; }

  22. 2.5再见括号君(Bracket_again) • 匹配 eg:(()()()) 模拟串数组s ( ( ) ( ) ( ) ) 匹配记录数组use -1 1 1 -1 -1 -1 1 -1 -1 1 -1 -1

  23. 2.5再见括号君(Bracket_again) • 匹配 int use[N<<1];//是否匹配数组 int res[N<<1];//结果数组 memset(use,-1,sizeof(use)); for(i=0;i<top;++i) { if(是“)”) { cnt=1;//计数清空 for(j=i-1;j>=0;--j) { if(s[j]=='('&&use[j]==-1)res[i]=cnt,use[j]=0,break; else cnt++; } } }

  24. 2.5再见括号君(Bracket_again) • 参考代码 char s[205]; int p[105],w[105]; int stack[105]; int res[25]; int main() { int t; int n; int ans; int i,j,top; scanf("%d",&t); while(t--) { scanf("%d",&n); for(i=0;i<n;++i)scanf("%d",&p[i]); for(i=0;i<p[0];++i) s[i]='('; s[p[0]]=')'; int key=p[0]+1; for(j=0;j<n-1;++j) { for(i=0;i<p[j+1]-p[j];++i) { s[key++]='('; } s[key++]=')'; } ans=0; memset(use,-1,sizeof(use)); for(i=0;i<key;++i) { if(s[i]==')') { cnt=1;//计数清空 for(j=i-1;j>=0;--j) { if(s[j]=='(') { if(use[j]==-1) { res[ans++]=cnt; use[j]=0; break; } else cnt++; } } } } printf("%d",res[0]); for(i=1;i<ans;++i) printf(" %d",res[i]); printf("\n"); } return 0; }

  25. 2.6高精度整数问题(calcu) • 问题描述: •  我们知道,int和__int64所能表示的范围有限,假如一个100位的数和100位的数相减,该怎么做? • 题目要求:计算n!-m!的结果。  (0<=m<=n<=100)。

  26. 2.6高精度整数问题(calcu) • 解题思路: • 1.n!和m!的结果超出整型表示的范围,所以只能用数组来保存最后的结果,每一位存数的一个位置上的数,所以每个位置的数的范围是0到9,如341在数组中表示是a[0]=3,a[1]=4,a[2]=1。 • 在运用中,我们把数的低位存在下标小的位置,高位存在下标大的位置如a[0]=1,a[1]=4,a[2]=3,为什么呢?为了方便进位

  27. 2.6高精度整数问题(calcu) • 2.n!要怎么算? • 模拟n!=1*2*3*4...*n的过程,将过程具体分解为n次乘法的过程,过程中结果都保存在数组中,如第一步,数组存a[0]=1,第二步,数组保存的数乘2,则每一位乘2,最后统一进位,比如乘到3时,数组中的数是a[0]=6,乘4时,a[0]就变成24,那么就要进位,最后变成a[1]=2,a[0]=4。 • 依次类推。。

  28. 2.6高精度整数问题(calcu) • 3.n!-m!怎么算? • (1)题目保证n>=m,所以答案是非负的,可以直接n!减去m!, • (2)2个数现在是保存在数组里面,要相减也要模拟一位位相减的过程,从低位开始相减,不够的就借位

  29. 2.6高精度整数问题(calcu) • 代码示例: • #include<stdio.h> • int a1[500],a2[500]; • void calc(int a[],int k) //数组乘以k,a[0]存位数 • { • int i,x; • for (i=1;i<=a[0];i++) //每一位乘以k • a[i]=a[i]*k; • for (i=1;i<a[0];i++) //每一位进位 • { • a[i+1]+=a[i]/10; • a[i]=a[i]%10; • } • x=a[0]; • while (a[x]>=10) //最高位进位 • { • a[x+1]+=a[x]/10; • a[x]=a[x]%10; • x++; • } • a[0]=x; • }

  30. 2.6高精度整数问题(calcu) • void minus(int a1[],int a2[]) //2数相减 • { • int i; • for (i=1;i<=a1[0];i++) • if (i<=a2[0]) //每一位相减 • a1[i]-=a2[i]; • else break; • for (i=1;i<a1[0];i++) //最后计算借位 • if (a1[i]<0) • { • a1[i]+=10; • a1[i+1]-=1; • } • while ((a1[0]>1)&&(a1[a1[0]]==0)) • a1[0]--; • }

  31. 2.6高精度整数问题(calcu) • int main() • { • int n,m,i; • scanf("%d%d",&n,&m); • a1[0]=1; a1[1]=1; • a2[0]=1; a2[1]=1; • for (i=1;i<=n;i++) • calc(a1,i); • for (i=1;i<=m;i++) • calc(a2,i); • minus(a1,a2); • for (i=a1[0];i>=1;i--) • printf("%d",a1[i]); • putchar('\n'); • return 0; • }

  32. Over~ Q&A

More Related