算法竞赛入门 (一)语言篇 数组和字符串

学习目标

  1. 一维数组的声明和使用
  2. 二维数组的声明和使用
  3. 字符串的声明、赋值、比较和连接
  4. ASCII码和ctype.h中的字符函数
  5. 正确认识“++”、“+=”等能修改变量的运算符
  6. fgetc和getchar的使用方法
  7. 了解不同操作系统中换行符的表示
  8. 掌握fgets的使用方法并了解gets的“缓冲区溢出”漏洞
  9. 学会用常量表简化代码

一、数组

程序1: 输入5个数,逆序输出

#include<stdio.h>
#define maxn 8
int a[maxn];
int main()
{
    int x, n = 0;
    while(scanf("%d", &x) == 1){
        a[n++] = x;
    }
    for(int j = n-1 ; j >= 0; j--)
        printf("%d ",a[j]);
    return 0;
}

 最后的^D 用来结束输入【即Ctrl +D】

# 在算法竞赛中,常常难以精确计算出需要的数组大小,数组一般会声明得稍 大一些。在空间够用的前提下,浪费一点不会有太大影响,所以即使是 输入5个数,保险起见完全可以定义数组大小为8

语句:a[n++]=x —— 做了两件事:首先赋值a[n]=x,然后执行n=n+1

#  对于变量n,n++和++n都会给n加1,但当它们用在一个表达式中时,行为有所差别:n++会使用加1前的值计算表达式【即n的原值】,而++n会使用加1后的值计算表达式【即n+1后的值】 ———— 谁在前面,就先用谁 【n++,n在前mian所以用n的原值,++n,++在前面,就将n先+1】

为什么要把a的定义放在main函 数的外面?

只有放在外面时,数组a的大小才可以开得很大;放在main函数内时,数组稍大就会异常退出

#  所以,比较大的数组应尽量声明在main函数外,否则程序可能无法运行

但数组不能进行赋值操作:

在程序3-1中,如果声明的是“int a[maxn],b[maxn]”,是不能赋值b=a的

如果要从数组a复制k个元素到数组b,可以这样做 —— memcpy(b,a,sizeof(int)*k)

当然,如果数组a和b 都是浮点型的,复制时要写成 —— memcpy(b,a,sizeof(double)*k)。另外需要注意的是, 使用memcpy函数要包含头文件string.h

如果需要把数组a全部复制到数组b中,可以写得简单 一些:memcpy(b,a,sizeof(a))

程序2:开灯问题

有n盏灯,编号为1~n。第1个人把所有灯打开,第2个人按下所有编号为2 的倍数的开关(这些灯将被关掉),第3个人按下所有编号为3的倍数的开关(其中关掉的灯 将被打开,开着的灯将被关闭),依此类推。一共有k个人,问最后有哪些灯开着?输 入n和k,输出开着的灯的编号。k≤n≤1000

样例输入:
7 3
样例输出:
1 5 6 7

我的思路: n个灯 k个人,如果 灯的编号 % 人的编号 == 0,就将灯的状态取反 ————>  可以利用 数组 + 双层for循环 + 状态值 实现

#include<stdio.h>
#include<string.h>
#define maxn 1010
int a[maxn];
int main()
{
    int n,k,first =1;
    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 % i == 0)
                a[j] = !a[j];
        }
    }
    for(int i = 1;i <= n;i++){
        if(a[i]){     //如果第i个灯是亮的,即a[i] = 1
            if(first)
                first = 0;
            else
                printf(" ");
            printf("%d",i);
        }
    }
    printf("\n");
    return 0;
}

技巧:

  1. memset(a,0,sizeof(a))—— 作用是把数组a清零,在string.h中定义
  2. 为了避免输出在最开始和最后输出多余空格,设置了一个标志变量first,可以表示当前要输出的变量是否为第一个。第一个变 量前不应有空格,但其他变量都有

采用样例数据测试时【即第1 5 6 7个灯是亮的】,可以在 程序 最后加入  printf("%d",a[1]); 输出结果是1,即 

a[j] = !a[j];

取反后,由0变1,或由1变0

程序3:蛇形填数

在n×n方阵里填入1,2,…,n×n,要求填成蛇形。例如,n=4时方阵为:

上面的方阵中,多余的空格只是为了便于观察规律,不必严格输出。n≤8。

我的思路:。。。我不会  =_=......  =__= .....=___=....

用二维数组解决 —— int a[n][n] ——> 然后从a[0][n] --> a[n][n]初始化 ---> a[n][n]--->a[n][0] ---->a[0][0]--->a[0][n-1]。。。。for循环 【但含有多次不定长的转向,短时间内无法做出来】

书的思路:

也是二维数组,从1开始依次填写。设“笔”的坐标为(x,y),则一开始x=0,y=n-1,即第0行,第n-1列 (行列的范围是0~n-1,没有第n列)。“笔”的移动轨迹是:下,下,下,左,左,左, 上,上,上,右,右,下,下,左,上。总之,先是下,到不能填为止,然后是左,接着是 上,最后是右。“不能填”是指再走就出界(例如4→5),或者再走就要走到以前填过的格子 (例如12→13)。如果把所有格子初始化为0,就能很方便地加以判断

#include<stdio.h>
#include<string.h>
#define maxn 20
int a[maxn][maxn];
int main()
{
    int n, x, y, tot = 0;
    scanf("%d", &n);
    memset(a, 0, sizeof(a));
    tot = a[x=0][y=n-1] = 1;//从1开始写
    while(tot < n*n)
    {
            while(x+1<n && !a[x+1][y])
                a[++x][y] = ++tot;    //【1】
            while(y-1>=0 && !a[x][y-1])
                a[x][--y] = ++tot;    //【2】
            while(x-1>=0 && !a[x-1][y])
                a[--x][y] = ++tot;    //【3】
            while(y+1<n && !a[x][y+1])
                a[x][++y] = ++tot;    //【4】
    }
    for(x = 0; x < n; x++)
        {
            for(y = 0; y < n; y++)
                printf("%3d", a[x][y]);
            printf("\n");
        }
    return 0;
}

【1】:这一行中,保持y不变,x每次移动加一,从上往下“填”数字,同时笔在往下移动的时候要满足 x不能超过n,因为是 n* n的数字阵列,且为了循环填完外层数后逐步循环填内层数,要保证下一次将要“填数”的位置   是0,即还没有填入数字【填上数后 !a[x][y] = 0】

 

 此时x = 0,y =2 在a[x][++y]打印16,即y = 3,此时开始循环判定,y + 1 <n  true,但  a[x][y+1] 已被填入 “1”,无法继续往右填,开始往下写(下一轮循环)

如果去除所有的预判是否过界:【去掉  &&  !a[x][y]  】

 其余过程同理

# 在很多情况下,最好是在做一件事之前检查是不是可以做,而不要做完再后 悔。因为“悔棋”往往比较麻烦

# 如果x+1<n为假,将不会计算“!a[x+1][y]”,也就不会越界 ———— &&是短路运算符 【这里提过】

为什么是++tot而不是tot++?

#include<stdio.h>

int main(){
    int i = 1;
    printf("%d\n",i);
    i++;
    printf("%d\n",i);
    ++i;
    printf("%d\n",i);
    return 0;
}

 回顾刚才提到的:

#  对于变量n,n++和++n都会给n加1,但当它们用在一个表达式中时,行为有所差别:n++会使用加1前的值计算表达式【即n的原值】,而++n会使用加1后的值计算表达式【即n+1后的值】 ———— 谁在前面,就先用谁 【n++,n在前mian所以用n的原值,++n,++在前面,就将n先+1】

二、字符数组

a

猜你喜欢

转载自www.cnblogs.com/expedition/p/11482813.html