机考解题详情
跳台阶(典型递归)
递归方法:
假如有n个台阶,那第n个台阶只能由第n-1或者第n-2的台阶跳上来
#include <stdio.h> int T(int n){ if(n == 0||n == 1) return 1; else return T(n-1)+T(n-2); } int main(){ int num; scanf("%d",&num); printf("%d",T(num)); return 0; }
迭代:
可以在数组中进行迭代依次求和
#include <stdio.h> #define N 1000 int main(){ int a[N],num; scanf("%d",&num); a[0] = 1; a[1] = 1; // 为了观看方便,a[0]不管; for(int i = 2;i <= num;i ++){ a[i] = a[i-1] + a[i-2]; } printf("%d",a[num]); return 0; }
回文日期(不难,注意数据处理)
直接上代码,注释里有部分解释
1 #include <stdio.h> 2 3 #define N 1000 4 5 int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; 6 //判断日期是否合法 7 int check(int date){ 8 int year = date/10000; 9 int month = date/100%100; 10 int day = date%100; 11 int flag = 1; 12 int leap; 13 14 15 if(!month || month>13 || !day) 16 flag = 0; 17 18 if(month != 2 && day > months[month]) 19 flag = 0; 20 21 if(month == 2){ 22 leap = (year % 4 == 0 && year % 100 || year % 400 == 0) ;//判断是不是闰年用到逻辑表达式 是就返回1,不是就返回0 23 24 if(day > 28 + leap ) 25 flag = 0; 26 } 27 return flag; 28 } 29 30 31 // 判断是否为回文日期 32 33 int Ispd(int date){ 34 int temp = 0; 35 36 while (date > temp){ 37 /* 38 终止条件本应该是date是否等于0 39 但由于我们知道给的数始终是偶数 40 所以只需要判断从尾部倒过来到中 41 间的数与从头但中间的数是否相等 42 就可以判断是否为回文数 43 */ 44 temp = temp * 10 + date%10; 45 date /= 10; 46 } 47 if(date == temp) 48 return 1; 49 else 50 return 0; 51 } 52 53 54 //判断是否为ABABBABA型日期 55 int IsAB(int date){ 56 int d,m; 57 d = date % 100; 58 m = date / 100 % 100; 59 60 if(Ispd(date) && d == m) 61 return 1; 62 else 63 return 0; 64 } 65 66 67 int main(){ 68 int Num; 69 scanf("%d",&Num); 70 71 for(int i = Num+1; i<89991231; i++){ 72 if(check(i) && Ispd(i)){ 73 printf("%d\n",i); 74 break; 75 } 76 } 77 for(int i = Num+1; i <= 89991231; i++){ 78 if(check(i) && IsAB(i)){ 79 printf("%d",i); 80 break; 81 } 82 } 83 84 return 0; 85 }
子串分值
思路:
1.计算一个子串的值:
(1)可以去重再累加去求个数
(2)通过一个大小为26所有元素为0的数组,将每个字符的值减去a的ASCLL的值,就是其在26字母中的位置,然后将该位置的值赋值为1(相同的字母永远赋值的是同一个位置),所以最后通过循环,加起来,就是这个子串的值
2.就是找子串,这个就通过两个值,一个代表起始一个代表末端,就ok了
1 #include <stdio.h> 2 3 char str[100000]; 4 5 int Judge(int x,int y){ // 求子串的值,也就是求一个字符串的不同的字母 6 int ans = 0; 7 int last[26]={0}; 8 int i; 9 for(i = x; i <= y; i ++){ 10 last[str[i]-'a'] = 1; 11 } 12 for(i = 0;i <= 25; i++){ 13 ans += last[i]; 14 } 15 return ans; 16 } 17 18 int main(){ 19 int count =0; 20 int ans = 0; 21 int k = 0; 22 int i,j; 23 scanf("%s",str); 24 while(str[k]){ 25 count++; 26 k++; 27 } 28 for(i = 0;i < count;i ++){ 29 for(j = i;j < count;j ++){ 30 ans += Judge(i,j); // 找子串,通过定下标,取出每个子串传进函数计算出子串值并求和 31 } 32 } 33 printf("%d",ans); 34 }
平面切分
思路:计算这些直线将平面分成了几个部分。
先去重,然后按照顺序每新增一个,新增的部分的个数=这一条线与前面的的线的交点个数+1,(暂时不用管后面学长讲)
1 #include<iostream> 2 #include<cstring> 3 #include<set> 4 using namespace std; 5 set<pair<double,double> > se; 6 const int N = 1005; 7 double A[N]; 8 double B[N]; 9 set<pair<double,double> > s; 10 set<pair<double,double> >::iterator it; 11 int main() 12 { 13 int n,i,j,x,y; 14 cin>>n; 15 for(i=0;i<n;i++) 16 { 17 cin>>x>>y; 18 s.insert(make_pair(x,y)); 19 } 20 n = s.size(); 21 for(i=0,it=s.begin(),it++;it!=s.end();it++,i++) 22 { 23 A[i]=(*it).first; 24 B[i]=(*it).second; 25 } 26 long long ans=2; 27 for(i=1;i<n;i++) 28 { 29 set<pair<double,double> > se; 30 for(j=i-1;j>=0;j--) 31 { 32 double x=(B[j]-B[i])/(A[i]-A[j]); 33 double y=(A[j]*B[i]-A[i]*B[j])/(A[j]-A[i]); 34 se.insert(make_pair(x,y)); 35 } 36 int n2=se.size(); 37 ans+=(n2+1); 38 } 39 cout<<ans<<endl; 40 }
跳跃游戏
最初的跳跃游戏是判断一个数组能否从头跳到尾,比如1 1 1 0 1;这种数组就不可能跳到尾,有兴趣的可以去做一下,可以直接用动态规划做
而我们这里的是在确保给定的数组是可以跳到尾的,让大家找到最小的跳跃次数
思路:动态规划要超时,所以用贪心算法(关于算法,后面有大佬给大家专门培训,可以去了解了解)
采用三个变量
cur:表示当前要覆盖到的最大小标
max:还没到cur结束之前的遍历到能覆盖的最大小标
res:用来表示结果
举个例子
[2,3,1,1,4];
一开始将res和cur初始化为0,分别表示步数为0和下标为0。max定义为一个小量(零或负数)。
利用贪心的思想,那么一开始(下标为0的位置)我就想走到最远的地方,也就是充分利用nums[0](也就是2)这个步长,但是,由于不知道在这个范围里面有没有更长的覆盖区间,那么,我就***先保留着这个当前最远的下标,也就是存入我的cur中。然后先看看在这个范围里面***有没有比当前最大值更大的,有的话先存到我的max中,如果遍历到了cur(i==cur)的时候,我就可以确定好在cur下标覆盖的范围里面我该走到多远了,也就是max(下标)。这就是循环的全部主体了。
值得注意的是我不需要遍历到最后一个,只需要遍历到倒数第二个就行了,因为到倒数第二个就已经可以确定最后结果了。
***如果上面看了还不懂:最开始能走的最大距离,然后记住这个下标,i循环到这个下标时,将这个下标内的最远覆盖距离max变成接下来的下一个要比较的下标,直到整个循环结束,有多少次这样的变化就是最少跳几次***
代码:
#include <stdio.h> int jump(int nums[], int numsSize){ if(numsSize<2) return 0; int i, j; int cur=0; int res=0; int max=-1; for(i=0;i<numsSize-1;i++) { max=max>i+nums[i]?max:i+nums[i]; // 记录最远覆盖距离 if(cur==i) // 一次最远距离结束的判断 { res++; cur=max; // 重新确定下一次的判断坐标 } } return res; } int main(){ int n; int nums[1000]; scanf("%d",&n); for(int i = 0;i < n;i ++) scanf("%d",&nums[i]); printf("%d",jump(nums,n)); return 0; }
最小方差
后面算法大佬给你讲,代码emmmm...,放了你们也不一定能看懂
#include <cmath> #include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int INF = 0x3f3f3f3f; int s[10][10], f[16][10][10][10][10]; int calc(int k, int x1, int y1, int x2, int y2) { int ans = INF; for (int i = x1 + 1; i < x2; i++) { ans = min(ans, f[k-1][x1][y1][i][y2] + f[1][i][y1][x2][y2]); ans = min(ans, f[k-1][i][y1][x2][y2] + f[1][x1][y1][i][y2]); } for (int i = y1 + 1; i < y2; i++) { ans = min(ans, f[k-1][x1][y1][x2][i] + f[1][x1][i][x2][y2]); ans = min(ans, f[k-1][x1][i][x2][y2] + f[1][x1][y1][x2][i]); } return ans; } int main() { int n; cin >> n; for (int i = 1; i <= 8; i++) for (int j = 1; j <= 8; j++) { scanf("%d", &s[i][j]); s[i][j] += s[i-1][j] + s[i][j-1] - s[i-1][j-1]; } for (int x1 = 0; x1 < 8; x1++) for (int y1 = 0; y1 < 8; y1++) for (int x2 = x1 + 1; x2 <= 8; x2++) for (int y2 = y1 + 1; y2 <= 8; y2++) { int p = s[x2][y2] - s[x1][y2] - s[x2][y1] + s[x1][y1]; f[1][x1][y1][x2][y2] = p * p; } for (int k = 2; k <= n; k++) for (int x1 = 0; x1 < 8; x1++) for (int y1 = 0; y1 < 8; y1++) for (int x2 = x1 + 1; x2 <= 8; x2++) for (int y2 = y1 + 1; y2 <= 8; y2++) f[k][x1][y1][x2][y2] = calc(k, x1, y1, x2, y2); printf("%.3f\n", sqrt((double)f[n][0][0][8][8] / n - (double)s[8][8] * s[8][8] / n / n)); return 0; }

浙公网安备 33010602011771号