320 likes | 480 Views
数组和函数题目讲解二 --陈静 031002402. 2.1数字矩阵(mat). 问题描述: 输出一个n 层的正方形数字矩阵。最外层是第一层数字为1,从外到内各层的数字依次对应1,2..,n,要求同一层的数字相同. 2.1数字矩阵(mat). 解题思路: 矩阵的形成:矩阵是一层层的形成方式,且每一层的数字是相同的! 解决方案:那我们也一层层地模拟矩阵的形成过程吧!. 2.1数字矩阵(mat).
E N D
数组和函数题目讲解二 --陈静 031002402
2.1数字矩阵(mat) • 问题描述: • 输出一个n 层的正方形数字矩阵。最外层是第一层数字为1,从外到内各层的数字依次对应1,2..,n,要求同一层的数字相同
2.1数字矩阵(mat) • 解题思路: • 矩阵的形成:矩阵是一层层的形成方式,且每一层的数字是相同的! • 解决方案:那我们也一层层地模拟矩阵的形成过程吧!
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列给模拟出来)
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;//右边界 • } • } • }
2.2寻找Key word(find) • 问题描述: • 给定N个数,要求从这N个数中拿出两个数,若这两个数的和与这两个数的差的绝对值皆为素数,称这一对数为Key word,并计数。要你计算出一共有多少对这样的数。
2.2寻找Key word(find) • 解题思路: • 1.首先我们要知道怎么判断一个数是否是素数!这时我们可以写一个函数实现该功能! • 2.我们要在这n个数中找出所有可能的不重复的2个数的组合,进而判断组合中2数的和与差的绝对值是否是素数!
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++) • {......}
主要代码: 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)
2.3 讨厌的ACM(acm) • 问题描述: • 一本只包含三个字母,A,C,M的书,这三个字母,而且排列毫无规律可言。希望你能将这些字母中含有“ACM”这个子串删除,删除后组成的新字母若还有包含,继续不断的删除,看最后剩下的字符串是什么? • 示例:输入:AAACMCM,输出:A
2.3 讨厌的ACM(acm) • 解题思路: • 1.每一次从字符串的第一个字符开始寻找是否有连续的ACM出现 • 2.若找到了,就删除该子串。怎么删除?把要删除子串后面的字符串往前移3个位置,然后返回步骤1,如果找不到就按顺序往后找。如果找完一遍都没找到就跳出循环输出最后的字符串
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];
代码示例: #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)
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'或者为空;
2.4zoj问题(zoj) • 解题思路: • 1. 3种能AC的字符串都有一个共同的特点:只有1个z, • 和1个j,且z在j前 • 2.在符合了以上的条件后,我们再分别判断是否符合3种情况的一个。 • (1)第一个和第二个条件可以直接判断也可归为一类就是xzojx,此时z前面o的个数和j后面o的个数是一样的且z,j之间只有一个o。
2.4zoj问题(zoj) • (2)第3种情况包含一种递归的概念。 • 要判断azboojaac是否可以AC就看azbojac是否可以AC, • 以此类推,一直递归到z,j之间的o只剩一个时或无法递归时,再判断是否符合第一种和第二种的情况,符合则说明azboojaac可以AC,不然就不能。 • 实现比较复杂,具体实现参见代码
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);
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之前
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; • }
2.5再见括号君(Bracket_again) 问题描述: 给出序列,每个数字代表每个“)”前有多少个“(” 输出序列,每个数字代表每个“)”与从其自身往前数第几个“(”匹配 题目保证能匹配(之前数据错了::>A<:: 解题思路: 根据序列模拟出原字符串 根据模拟后的字符串匹配输出
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++]=')'; }
2.5再见括号君(Bracket_again) • 匹配 eg:(()()()) 模拟串数组s ( ( ) ( ) ( ) ) 匹配记录数组use -1 1 1 -1 -1 -1 1 -1 -1 1 -1 -1
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++; } } }
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; }
2.6高精度整数问题(calcu) • 问题描述: • 我们知道,int和__int64所能表示的范围有限,假如一个100位的数和100位的数相减,该怎么做? • 题目要求:计算n!-m!的结果。 (0<=m<=n<=100)。
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,为什么呢?为了方便进位
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。 • 依次类推。。
2.6高精度整数问题(calcu) • 3.n!-m!怎么算? • (1)题目保证n>=m,所以答案是非负的,可以直接n!减去m!, • (2)2个数现在是保存在数组里面,要相减也要模拟一位位相减的过程,从低位开始相减,不够的就借位
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; • }
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]--; • }
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; • }
Over~ Q&A