算法竞赛入门经典(第2版)笔记--第3章

头文件string.h中常用函数用法

1.需要包含头文件string.h

2.将数组a清零:memset(a,0,sizeof(a));

3.从数组a复制k个元素到数组b(数组元素为int类型):
     memcpy(b,a,sizeof(int)*k);
  若把数组a全部复制到数组b中,则为memcpy(b,a,sizeof(a));

4.char *strchr(const char* _Str,char _Val)
   功能:查找字符串_Str中首次出现字符_Val的位置
   返回值:成功则返回要查找字符第一次出现的位置,失败返回NULL

5.extern unsigned int strlen(char *s);
   功能:计算给定字符串的(unsigned int型)长度,不包括’\0’在内
   说明:返回s的长度,不包括结束符NULL。
   注:s[strlen[s]]=’\0’

有关输入的细节

1.int fgetc(FILE * stream);
  fgetc(fin)可以从打开的文件fin中读取一个字符,一般情况下应该在检查它不是EOF后再将其转换成char值。

  int getchar(void);
  getchar()可以从标准输入读取一个字符,相当于fgetc(stdin)

   注:fgetc和getchar将读取下一个字符,如果用scanf(“%d”,%n)读取整数n,要是在输入123后多加了一个空格,用getchar读取的将是这个空格;如果在123后紧跟着换行,则读取到的将是回车符”\n”。

2.char *fgets(char *buf, int bufsize, FILE *stream);
  参数:
    *buf: 字符型指针,指向用来存储所得数据的地址。
    bufsize: 整型数据,指明存储数据的大小。
    *stream: 文件结构体指针,将要读取的文件流。

  fgets(buf,maxn,fin)将读取完整的一行放在字符数组buf中。应当保证buf能够存放下文件的一行内容。除了在文件结束前没有遇到”\n”这种特殊情况外,buf总是以”\n”结尾(之后是字符串结束符”\0”)。函数成功将返回buf,失败或读到文件结尾返回NULL。因此我们不能直接通过fgets的返回值来判断函数是否是出错而终止的,应该借助feof函数或者ferror函数来判断。
    键盘输入fgets(buf,n,stdin)

3.int sprintf( char *buffer, const char *format, [ argument] … );
  参数列表
    buffer:char型指针,指向将要写入的字符串的缓冲区。
    format:格式化字符串。
    [argument]…:可选参数,可以是任何类型的数据。
  功能是把格式化的数据写入某个字符串中,用法与printf类似

第3章例题与习题代码及分析

例3-1 Tex中的引号(Tex quotes,UVa 272)

  本题主要在于字符串的输入及左右引号的判断,注意有空格的字符串不能用scanf(“%s”)读入,引号判断通过设置标志变量即可。

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

例3-2 WERTYU (WERTYU,UVA10082)

此题关键在于输入输出变换,用if语句判断太繁琐,用常量数组会简化不少(无需指明数组大小)

#include<stdio.h>
char s[]="`1234567890-=QWERTYUIOP[]\\ASDFGHJKL;'ZXCVBNM,./'";  //定义一个常量数组 (其中\需用\\转义得到)
int main(){
    int i,c;
    while ((c=getchar())!=EOF){
        for (i=0;s[i]&&s[i]!=c;i++);  //查找错位之后的字符在常量表中的位置 
        if (s[i])                     //如果找到,则输出它的前一个字符 
            putchar(s[i-1]);
        else
            putchar(c);
    }
    return 0;
} 

注:putchar函数的基本格式为:putchar(c)。
(1)当c为一个被单引号(英文状态下)引起来的字符时,输出该字符(注:该字符也可为转义字符);
(2)当c为一个介于0~127(包括0及127)之间的十进制整型数时,它会被视为对应字符的ASCII代码,输出该ASCII代码对应的字符;
(3)当c为一个事先用char定义好的字符型变量时,输出该变量所指向的字符。

例3-3 回文词 (Palindromes UVa401)

此题回文的判断较为容易,而镜像的判断通过定义一个常量字符数组,按顺序存储A-Z,0-9这些字符的镜像字符(若不存在镜像字符则为空格符)。输出也有两个技巧进行简化,一是通过定义常量字符串数组,二是通过p,m省去多次if判断。

#include <stdio.h>
#include <string.h>
const char rev[]="A   3  HIL JM O   2TUVWXY51SE Z  8 ";
const char* msg[]={
  "not a palindrome","a regular palindrome","a mirrored string","a mirrored palindrome"};
bool isPalindrome(char s[]){
    int len=strlen(s);
    for (int i=0;i<len/2;i++)
        if (s[i]!=s[len-i-1])
            return false;
    return true;
}
bool isMirrored(char s[]){
    int len=strlen(s);
    for (int i=0;i<len;i++){
        char ch=s[i];
        if ((ch>='A' && ch<='Z'&& s[len-i-1]!=rev[ch-'A']) || 
               (ch>='1' && ch<='9' && s[len-i-1]!=rev[26+ch-'1']))
            return false;
    }   
    return true;
}
int main(){
    char s[30];
    while (scanf("%s",s)==1){
        /*if (isPalindrome(s))
            if (isMirrored(s))
                printf("%s -- is %s.\n\n",s,msg[3]);
            else
                printf("%s -- is %s.\n\n",s,msg[1]);
        else if (isMirrored(s))
                printf("%s -- is %s.\n\n",s,msg[2]);
            else
                printf("%s -- is %s.\n\n",s,msg[0]);
        */ 
        int p=1; int m=1;
        if (!isPalindrome(s)) p=0;
        if (!isMirrored(s)) m=0;
        printf("%s -- is %s.\n\n",s,msg[m*2+p]);
    }
} 

例3-4 猜数字游戏的提示 (Master-Mind Hints, UVa340)

分析:直接统计可得A,求B:对于每个数组1-9,统计二者出现的次数count1,count2,则min(count1,count2)再减去A即为在两个序列都出现过但位置不对的个数。

#include <stdio.h>
#define MAXN 1005
int main(){
    int a[MAXN],b[MAXN];
    int n,i,game=0;
    while (scanf("%d",&n)==1 && n){
        for (i=0;i<n;i++)
            scanf("%d",&a[i]);
        printf("Game %d:\n",++game);
        do{
            int strongMatch=0;
            for (i=0;i<n;i++){
                scanf("%d",&b[i]);
                if
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值