【学习记录】算法竞赛入门经典(第二版)

【学习小感】
因为每次做完一个习惯性直接删,但是感觉又有点可惜,留着又不想建一堆文件,故贴一个。(2020/7)
7月份开始断断续续学这本书,作为一个非cs科班同学,本科C语言基础大多来自计算机二级的刷题。八月份主要在准备图论期末考试,九月份过了大众校企班的笔试面试。十月份第一次参加IEEEEXTREME极限编程大赛,试着加快了啃书速度,但是发现还是自己静下心来做过的那些题有用,在比赛的时候能感觉到有不少做过的题的影子。最开始还是按照自己的写码思路写书上的题目,不会的时候就敲一敲书上的代码,后来逐渐迁移学习模仿书上的代码风格,确实比自己的高级很多。感谢我刚开始写代码时师父的辅导,没有师父我真的可能开始都坚持不下来。也感谢师父现在也会陪我改bug,最后感谢学妹陪我一起打比赛写C++,持续24小时的编程,最终进了top10%,真的太不容易了。(2020/10)

第一章

例题1-4 鸡兔同笼

#include <stdio.h>
#include <math.h>
int main()
{
    int m,n,x,y;
    scanf("%d%d",&n,&m);
    y = (m - 2*n)/2;
    x = n - y;
    if (x >= 0 && y >=0 && x % 2 == 0 && y % 2 == 0) {
        printf("chicken is %d rabbit is %d",x,y);
    }
    else {
        printf("no answer");
    }
}

for循环

#include <stdio.h>
int main(){
    int n;
    scanf("%d",&n);
    for(int i = 1; i <= n; i++){
        printf("%d\n",i);
    }
    return 0;
}

第二章

例题2-1 输出所有aabb形完全平方数

#include <stdio.h>
#include <math.h>
int main(){
//    float n;
//    int m;
    for (int a = 1; a <= 9; a++){
        for (int b = 1; b <= 9; b++){
            int n = a*1100 + b*11; //构成aabb
            //printf("%d\n",n);
            float m = sqrt(n);
            m = floor(m+0.5);
            if (m*m == n){
                printf("Yes,%d",n);
            }
        }
    }
    return 0;
}

输出真是7744

例题2-2 3n+1

#include <stdio.h>
#include <math.h>
int main(){
//    float n;
//    int m;
    int m,n;
    m = 0;
    scanf("%d",&n);
    while (n>1){
        m++;
        if (n % 2 == 1){
            n = 3*n + 1;
        }
        else{
            n = n/2;
        }
    }
    printf("%d\n",m);
    return 0;
}

例题2-3 近似计算

#include <stdio.h>
#include <math.h>
int main(){
    double sum = 0;
    for(int i = 0; ; i++){
        double term = 1.0/(2*i + 1);
        if (i % 2 == 0){   //double
            sum = sum + term;
        }
        else sum = sum - term;
        if (term<1e-6) break;
    }
    printf("%.4f",sum);
    return 0;
}

用于查看代码运行时间

#include <time.h>
printf("%.2f\n",(double)clock()/CLOCKS_PER_SEC);

例题2-4 阶乘之和 保留后六位

int main(){
    int n,sum=0,term=1;
    scanf("%d",&n);
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= i; j++){
            term = term * j;
        }
        sum = sum + term;
        term = 1;
    }
    printf("%d",sum % 100000);
    return 0;
}

例题2-5 数据统计

在这里插入代码片#include <stdio.h>
#include <math.h>
//数据统计
int main(){
    int x, n = 0,s = 0; //n为j计数器
    long min = 10000, max = - 10000;
    while (scanf("%d", &x) == 1){
        s += x;
        if (x>=max){
            max = x;
        }
        else if (x<=min){
            min = x;
            n++;
        }
    }
    printf("%d %d %.3f\n", min, max, (double)s/n);
}

习题2
1 水仙花数

2 韩信点兵

#include <iostream>
#include <string>
using namespace std;

int main(){
    int a,b,c;
    int flag = 0;
    cin>>a;
    cin>>b;
    cin>>c;

    for (int i=1; i<100; i++){
        if((i%3==a)&&(i%5==b)&&(i%7==c)){
            cout<<i<<endl;
            flag = 1;
        }
    }

    if (flag ==0){
        cout<<"no answer"<<endl;
    }
    system("pause");
}

3 倒三角形
【这道题用反向计数(递减)会方便很多】

#include <iostream>
#include <string>
using namespace std;

int main(){
    int n;
    cin>>n>>endl;
    for (int i=1;i<=n;i++){ //行数
        if (i==1){
            for (int t=1;t<=2*n-1;t++){
                cout<<"#";
            }
        cout<<endl;
        }
        else{
            for (int x=1;x<i;x++){
                cout<<" ";
            }
            for (int y=i;y<2*n-i;y++){
                cout<<"#";
            }
            for (int z=2*n-i;z<2*n;z++){
                cout<<" ";
            }
            cout<<endl;
        }    
    }
    system("pause");
}

这个报错了我不知道为什么【更新:cin不能写endl】
我过会去试一试
更新:这里报错是输入的问题 参考了其他的用c重新写了一下是对的
这个方法更加的简洁

#include <stdio.h>
#include <stdlib.h>

int main(){
   int i,j,k,n;
   scanf("%d",&n);
   for (i=n;i>0;i--){
      for (j=0;j<n-i;j++){
         printf(" ");
      }
      for (k=0;k<2*i-1;k++){
         printf("#");
      }
      printf("\n");
   }
   //return 0;
   system("pause");
}

4 子序列的和
【这道题因为涉及到了平方,所以样例输入中有一个655360太大了会溢出】
【解决方法有两个,一个是用longlong int(亲测long不够),还有一个是用1/n/n(这个好聪明啊)】

#include <stdio.h>
#include <stdlib.h>

int main(){
   int m,n;
   double sum=0.0;
   int a[100],b[100];
   int flag=0;
   while(1){
      scanf("%d",&n);
      scanf("%d",&m);
      a[flag]=n;
      b[flag]=m;
      if (m==0&&n==0){
         break;
      }
      flag++;
   }

   printf("%d\n",flag);

   for (int j=0;j<flag;j++){
      for (long long i=a[j]; i<=b[j]; i++){
         sum += 1.0/double(i*i);
         //printf("in");
      }
   
   printf("Case %d ",j+1);
   printf("%.5f\n",sum);
   sum =0.0;
   }

   system("pause");
}

这个数组实际上是有问题的,我还不知道怎么处理这个问题qwq

5 分数化小数

【1.我在调代码的过程中发现,如果使用%f对一个int型输出,会输出0.0000,并不如想象中的会输出带小数的这个数。
正确方法:对(float)a进行%f输出。
【2.这种000结束输入的时候,做flag或者是count在000判断以后再计数会更好理解。
000读入以后直接break,不进入计数。
【3.printf的特殊用法—*控制输出宽度和精度
控制输出精度
正常是eg %.2f
小数点后.的数字表示输出精度位数
(同样的方法也可用于输出字符串)
printf格式字符串、数,与宽度控制和精度控制有关的常量都可以换成变量

在格式输出的"%.*f\n",1(用于替代当中的星号),变量。

#include <stdio.h>
#include <stdlib.h>

int x,y,z;
int a[10];
int b[10];
int c[10];
int flag = 0;

int main(){
   //输入
   while(1){
      scanf("%d",&x);
      scanf("%d",&y);
      scanf("%d",&z);
      a[flag]=x;
      b[flag]=y;
      c[flag]=z;
      //printf("a flag is %d\n",a[flag]); //测试是不是读入
      if (x==0&&y==0&&z==0){
         break;
      }
      flag++;
   }
   //printf("%d\n",flag);  //多少组数据

   for (int i = 0;i<flag;i++){
      printf("Case %d : %.*f\n",i+1,c[i],(float)a[i]/b[i]);
   }

   system("pause");
}

6 排列
用1~9组成三个三位数,每个数字恰好用一次,要求1:2:3

#include <stdio.h>
#include <stdlib.h>
int a[9]={0,0,0,0,0,0,0,0,0};
int real_flag=0;
int c =0;
int judge(int num1, int num2, int num3){
   a[0]=num1/100; //bai
   a[1]=num1%100/10; //shi
   a[2]=num1%10; //ge
   a[3]=num2/100; //bai
   a[4]=num2%100/10; //shi
   a[5]=num2%10; //ge   
   a[6]=num3/100; //bai
   a[7]=num3%100/10; //shi
   a[8]=num3%10; //ge

   int flag=0;
   for (int j=0;j<9;j++){
      for(int k =j+1;k<9;k++){
         if(a[j]==a[k]){
            flag++;
         }
         if(a[j]==0){
            flag++;
         }
      }

   }
   if (flag==0){
      real_flag++;
   }
   
   return real_flag;
}

int main(){
   for (int i = 100; i<334; i++){ //abc
      int def = 2*i, ghi = 3*i;
      int b = judge(i, def, ghi);
      if (b>c){
         printf("%d %d %d\n",i,def, ghi);
      }
      c=b;

   }
   system("pause");
}

第三章 数组和字符串

3.1 数组
例题1 逆序输出

#include <stdio.h>
#include <stdlib.h>
//读入一些整数,逆序输出
#define maxn 105
int a[maxn];

int main()
{
   int x,n=0;
   while(scanf("%d",&x)==1){
      a[n++]=x;
   }
   for (int i=n-1;i>=0;i--){
      printf("%d ",a[i]);
   }
   printf("%d\n",a[0]);
   system("pause");
}

例题2 开灯问题

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxn 1010
int a[maxn];

int main()
{
   int n,k;
   memset(a,0,sizeof(a));
   scanf("%d%d",&n,&k);
   for (int i=1;i<=k;i++){
      for (int j=1;j<=n;j++){
         if (j%k==0){
            a[j]++;
         }
      }
   }

   for (int k=1;k<=n;k++){
      if (a[k]%2==0){
         printf("%d is off", k);
      }
      else printf("%d is on",k);
   }

   system("pause");
}

例题3 蛇形数组

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//蛇形填数
#define maxn 10
int a[maxn][maxn];

int main(){
   int x,y,n; //输入n*n大小的正方型
   int max,min; //用于记录每次的循环的最大最小值
   scanf("%d",&n);
   memset(a, 0, sizeof(a)); //清零数组a
   max = n-1;
   min = n-1-max;//默认为0
   //每一次循环填数都是下左上右的一个过程
   for (int i=0;i<n*n;){
      //if(min>=max){break;}
      //考虑开始的最大值的【数组】坐标 a[0][max-1]
   //下
      for (int j=min; j<=max; j++){
         if (i>=n*n) break;
         a[j][max]=++i;
      }
   //左
      for (int k=max-1; k>=min; k--){
         if (i>=n*n) break;
         a[max][k]=++i;
      }
   //上
      for (int l=max-1; l>=min; l--){
         if (i>=n*n) break;
         a[l][min]=++i;
      }
   //右
      for (int m=min;m<max-1;m++){
         if (i>=n*n) break;
         a[min][m+1]=++i;
      } 
      if (i>=n*n) break;
      max--;
      min = n-1-max;
   }

   //输出数组
   for (int x=0;x<n;x++){
      for (int y=0;y<n;y++){
         printf("%3d",a[x][y]);
      }
      printf("\n");
   }

   system("pause");
}

例题4 竖式问题

//竖式问题
//找出形如abc*de的
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(){
   char s[20],buf[99];
   int num = 0;
   scanf("%s",s); //输入字符串
   for (int abc=111;abc<=999;abc++){
      for (int de=11;de<=99;de++){
         int x =abc*(de%10), y=abc*(de/10), z=x+10*y; //分别定义后个位相乘结果,十位相乘结果,总乘积
         sprintf(buf,"%d%d%d%d%d",abc,de,x,y,z);
         int flag = 1;
         //检测buff中每个字符是不是都与s中重合
         for(int i=0; i<strlen(buf); i++){
            if (strchr(s,buf[i])==NULL){
               flag = 0;
            }
            //如果重合,说明这一组里的数字是可以用的,进行一次样例输出
         }
         if (flag){
               printf("<%d>\n",++num);
               printf("%5d\nX%4d\n-----\n%5d\n%4d\n-----\n%5d\n\n", abc, de, x, y, z);
            }
      }
   }
   printf("The number of solutions = %d", num);
   system("pause");
}

【例题3-1 TEX中的引号】
这个是书上写的

#include <stdio.h>
#include <stdlib.h>

int main(){
	int c,q =1;
	while((c = getchar())!=EOF){
		if (c == '"'){
			printf("%s",q ? "``" : "''");
			q = !q;
		}
		else printf("%c",c);
	}
	system("pause");
}

然后这个是我写的

#include <stdio.h>
#include <stdlib.h>
int main(){
    int c, flag = 0;
    while((c = getchar())!=EOF){
        if (c == '"'){
            if (flag == 0){
                printf("%s", "``");
            }
            else{
                printf("%s", "''");
            }
            flag = !flag;
        }
        else printf("%c",c);
    }
}

⚠️注意点
1.注意输出双引号
’ ’ 引起的一个字符代表一个整数,整数值对应于该字符在编译器采用的字符集中的序列值;
” ”引起的字符串代表的是一个指向无名数组起始字符的指针。
C语言中的单引号用来表示字符字面量
C语言中的双引号用来表示字符串字面量(指针)
2.getchar返回值类型为int ASCII码
在这里插入图片描述

以及char型变量其实也是数字。
如果要定义字符串:
char s[] = “abcde”;
但是这个字符数组中每个字符也是按ASCII码存储的,如果不是按c输出的话应该也是一个int整数。

【例题3-2 WERTYU】
【注意点】

  1. 因为\是转义字符,所以字符串里面要输出\就必须写成\
  2. 思路是用getchar()先输入字符,输入字符再数组中寻找是否有相同/对应的字符。
  3. c语言中的读取数组长度:用sizeof(数组)
    我有看到说要除以数据类型长度的,但是我尝试了字符串数组就是sizeof(字符串数组)
    在这里插入图片描述

· 字符串数组好像是可以不写大小直接写
在这里插入图片描述
但是数字数组好像不行

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char s[] = "`1234567890-=QWERTYUIOP[]ASDFGHJKL;'\\ZXCVBNM,./";
int main(){
   int c;
   printf("%d\n",sizeof(s));
   while((c=getchar())!=EOF){ //输入
      for (int i=0; i<sizeof(s); i++){
         if (s[i]==c){
            printf("%c\n",s[i-1]);
         }
      }
   }
   system("pause");
}

例题3-4 猜数字游戏的提示
题目要求读入一组答案 一组猜测
猜测中,A为答案和猜测中数字相同且位置相同的个数
B为数字相同但位置不同的个数
题目答案给了一个方法求解B:统计答案和猜测中1-9中数字的出现频次,取最小值,再减去A就是数字相同但位置不同的个数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int maxn = 100;
int a[maxn],b[maxn];

int main(){
    int n;
    int count = 0;
    while(scanf("%d",&n)&&n!=0){ //n!=0
        //读入正确答案
        printf("Game %d:\n",++count);
        for (int i = 0;i < n; i++){
            scanf("%d",&a[i]);
        }
        //读入猜测
        for (; ;){
            int flag = 0;
            int A=0, B=0;
            for (int i = 0;i < n; i++){
                scanf("%d",&b[i]);
                if(b[i]==0) flag++;
                if(b[i]==a[i]) A++;
            }
            if (flag == n) break;
            //统计a和b中1-9出现的频次 按最小的计数
            for (int i = 1; i < 10; i++){
                int c1=0,c2=0;
                for (int j = 0; j < n; j++){
                    if(a[j]==i) c1++;
                    if(b[j]==i) c2++;
                }
                //比较当前数字中c1和c2的大小,取小
                if (c1>c2) B = B + c2;
                else B = B + c1;
            }
            //统计完后B需要减掉A
            printf("(%d,%d)\n",A,B-A);
        }
    }
    system("pause");
}

第四章 函数和递归

第五章 STL入门

例题5-1 大理石在哪儿
本题主要难度在于搞清楚输入。在这些练习下对于输入已经有了一定的理解,所以不是很难。然后就是stl中的两个函数,sort和lower_bound

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn = 100;

int main(){
	int n,q,a[maxn],count=0,x; //n:n个石头,q:q个问题
	while(scanf("%d%d",&n,&q)==2&&n){
		printf("Case# %d\n",++count);
		for (int i = 0; i < n ; i++){
			scanf("%d",&a[i]);
		}
		sort(a,a+n);
		printf("sorted result is:");
		for (int i = 0; i < n; i++){
			printf("%d",a[i]);
		}
		printf("\n");
		while(q--){
			scanf("%d",&x);
			if(binary_search(a,a+n,x)){
				int *t = lower_bound(a,a+n,x);
				printf("%d found at %d", x, t-a+1);
			}
			else printf("%d not found", x);
		}
	}
	system("pause");
}

c++:结构体与排序

#include <iostream>
#include <algorithm>
#include "cstring"
#include <stdlib.h>
using namespace std;
struct Student
{
	char name[20];
	int math;
	int english;
};

bool cmp(Student a, Student b);

int main(){
	Student a[4] = {{"apple",67,89},{"banana",90,56},{"apple",90,99}};
	sort(a,a+3,cmp);
	for (int i = 0;i < 3; i++ ){
		cout << a[i].name <<" "<<a[i].math<<" "<<a[i].english << endl;
	}
	system("pause");
}

bool cmp(Student a, Student b){
	if (a.math != b.math){
		return a.math>b.math;
	}
	else return a.english > b.english;
}

例题5-2 木块问题
用vector表示每个高度 定长数组表示木块堆

#include <cstdio>
#include <string>
#include <vector>
#include <iostream>
using namespace std;

const int maxn= 30;
int n;
vector<int> pile[maxn]; //声明pile数组,数组每个元素都是一个vector
//堆:0~n-1共n堆
//pile:堆号 height:堆的高度
//寻找出木块a在的pile和height
void find_block(int a, int &p, int &h){
	for (p=0; p<n; p++)
		for (h=0; h<pile[p].size();h++)
			if(pile[p][h]==a) return; 
}

//删除第p堆高度为h以上的所有木块【移回原来的堆】
void clear_above(int p,int h){
	for (int i=h+1; i<pile[p].size(); i++){
		int b=pile[p][i];
		pile[b].push_back(b);
	}
	pile[p].resize(h+1);
}

void pile_onto(int p, int h, int p2){
	for (int i=h; i<pile[p].size();i++){
		pile[p2].push_back(pile[p][i]);
	}
	pile[p].resize(h); //只保留0~h-1
}

void print(){
	for (int i=0; i<n; i++){
		printf("%d",i);
		for (int j=0; j<pile[i].size();j++) printf(" %d", pile[i][j]);
		printf("\n");
	}
}

int main(){
	int a,b;
	cin >> n;
	string s1, s2;
	for (int i = 0; i<n; i++) pile[i].push_back(i); //堆的初始化
	while(cin >> s1 >> a >> s2 >> b){
		// cin >> a;
		// cout << a << endl;
		int pa, pb, ha, hb;
		find_block(a, pa, ha);
		find_block(b, pb, hb);
		if (pa ==pb) continue;
		if (s2 == "onto") clear_above(pb, hb);
		if (s1 == "move") clear_above(pa, ha);
		pile_onto(pa, ha, pb);
		//print();
	}
	print();
	system("pause");
}

例题5-3 字典集合set

#include <iostream>
#include <string>
#include <set>
#include <vector>
#include <sstream>
#include <stdlib.h>
using namespace std;

set<string> dict;

int main(){
    string s, buf;
	while(cin >> s){
		for (int i = 0; i <s.length(); i++)
			if (isalpha(s[i])) s[i]=tolower(s[i]); else s[i] = ' ';
		stringstream ss(s);
		while(ss >> buf) dict.insert(buf);
	}
	for (set<string>::iterator it = dict.begin(); it != dict.end(); ++it)
		cout << *it << "\n";
	system("pause");
}

第六章 数据结构基础

例题6-2 铁轨

#include <stdio.h>
#include <stack>
#include <stdlib.h>
using namespace std;
const int maxn = 100;

int n, target[maxn];

int main(){ 
	while(scanf("%d",&n)==1){
		stack<int> s;
		int A = 1, B = 1;
		for (int i=1; i<=n; i++){
			scanf("%d", &target[i]);
		}
		//输入n节车厢,出栈顺序结果用target数组描述
		int ok = 1;
		while(B <= n){
			// if(A == target[B])
			// {
			// 	A++; 
			// 	B++;
			// }
			//这段没有也可以运行,但是有会提高速度
			if(!s.empty()&&s.top()==target[B])
			{
				s.pop();
				B++;
			}
			else if(A <= n) s.push(A++);
			else {ok = 0; break;}
		}
		printf("%s\n",ok?"Yes":"No");
	}
	system("pause");
}

例题6-3 矩阵链乘

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <stack>
#include <string>
using namespace std;

/*
计算矩阵链乘表达式的乘法次数
如果乘法无法进行,输出error
矩阵名:A-Z 矩阵结构:axb
*/

//矩阵结构体,26是26个字母,对应矩阵A-Z
struct Matrix{
    int a,b;
    Matrix(int a=0, int b=0):a(a),b(b){}
}m[26];

stack<Matrix> s; //记录矩阵计算过程

int main(){
    int n;
    cin >> n; //有n组输入,即输入n个矩阵 
    for(int i = 0; i<n; i++){
        string name;
        cin >> name;
        int k = name[0] - 'A';
        cin >> m[k].a >> m[k].b;
    }
    for (int i =0; i<26; i++){
        cout << "a" << m[i].a << "b" <<m[i].b << endl;
    }
    string expr;
    while (cin >> expr){
        int len = expr.length();
        bool error = false;
        int ans = 0;
        for (int i = 0; i < len; i++){
            if(isalpha(expr[i])) s.push(m[expr[i]-'A']);
            else if(expr[i] == ')'){
                Matrix m2 = s.top(); s.pop();
                Matrix m1 = s.top(); s.pop();
                if(m1.b != m2.a) { error = true; break; }
                ans += m1.a * m1.b * m2.b;
                s.push(Matrix(m1.a, m2.b));
            }
        }
        if(error) printf("error\n"); else printf("%d\n", ans);
    }
    system("pause");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值