zoukankan      html  css  js  c++  java
  • 算法竞赛入门 (一)语言篇 数组和字符串 2

    三、竞赛题目选讲

    例题3-2 WERTYU

    把手放在键盘上时,稍不注意就会往右错一位。这样,输入Q会变成输入W,输入J会变成输 入K等。输入一个错位后敲出的字符串(所有字母均大写),输出打字员本来想打出的句子。输入保证合法,即一定是错位之后的字符串。例如输入中不会出现大写字母A。

    样例输入:
    O S, GOMR YPFSU/
    样例输出:
    I AM FINE TODAY

    我的思路:这样的打字员赶紧滚犊子完事

    同例题3-1,可以利用 getchar()  一边输入,一边输出。但问题卡在了 如何变换回正确的? switch 或 if 都太麻烦

    书的思路:使用常量数组

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

     # 常量数组并不需要指明大小,编译器可以完成计算

     例题3-3 回文词

    输入一个字符串,判断它是否为回文串以及镜像串。输入字符串保证不含数字0。所谓 回文串,就是反转以后和原串相同,如abba和madam。所有镜像串,就是左右镜像之后和原

    串相同,如2S和3AIAE。注意,并不是每个字符在镜像之后都能得到一个合法字符。在本题 中,每个字符的镜像如图3-3所示(空白项表示该字符镜像后不能得到一个合法字符) 

     

    输入的每行包含一个字符串(保证只有上述字符。不含空白字符),判断它是否为回文 串和镜像串(共4种组合)。每组数据之后输出一个空行。
    样例输入:
    NOTAPALINDROME
    ISAPALINILAPASI
    2A3MEAS
    ATOYOTA
    样例输出:
    NOTAPALINDROME -- is not a palindrome.
    ISAPALINILAPASI -- is a regular palindrome.
    2A3MEAS -- is a mirrored string.
    ATOYOTA -- is a mirrored palindrome.

    分析:题目提到了 不包含空白字符 —— 可以安全的用 scanf 进行输入

    可以采用上方例题提到的 常量数组解决

    #include<stdio.h>
    #include<string.h>
    #include<ctype.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"};
    
    char r(char ch) {
          if(isalpha(ch))
            return rev[ch - 'A'];
          return rev[ch - '0' + 25];
    }
    int main() {
          char s[30];
          while(scanf("%s", s) == 1) {
                int len = strlen(s);
                int p = 1, m = 1;
                for(int i = 0; i < (len+1)/2; i++) {
                            if(s[i] != s[len-1-i])
                            p = 0; //不是回文串
                            if(r(s[i]) != s[len-1-i])
                                m = 0; //不是镜像串
                            }
                printf("%s -- is %s.
    
    ", s, msg[m*2+p]);
    
        }
       return 0;
    }

    自定义函数char r(char ch),参数ch是一个字符,返回值是ch的镜像字符。这是因为该常量数组中前26项是各个大写字母的镜像,而后10个是数字1~9的镜像(数 字0不会出现),所以需要判断ch是字母还是数字

    isalpha来判断字符是否为字母,类似的还有idigit、isprint等,在ctype.h中定义。

    由于ASCII码表中大写字母、小写字母和数字都是连续的,如果ch是大写字母,则ch-'A'就是 它在字母表中的序号(A的序号是0,B的序号是1,依此类推);类似地,如果ch是数字, 则ch-'0'就是这个数字的数值本身(例如'5'-'0'=5)

    常量数组msg,事实上,这是一个字符串数组,即二维字符数组

     # 头文件ctype.h中定义的isalpha、isdigit、isprint等工具可以用来判断字符 的属性,而toupper、tolower等工具可以用来转换大小写。如果ch是大写字母,则ch-'A'就是 它在字母表中的序号(A的序号是0,B的序号是1,依此类推);类似地,如果ch是数字, 则ch-'0'就是这个数字的数值本身

    char* a = "abc" 和 char a[] = "abc" 之间的区别

     例题3-4 猜数字游戏的提示

    实现一个经典"猜数字"游戏。给定答案序列和用户猜的序列,统计有多少数字位置正确 (A),有多少数字在两个序列都出现过但位置不对(B)。
    输入包含多组数据。每组输入第一行为序列长度n,第二行是答案序列,接下来是若干 猜测序列。猜测序列全0时该组数据结束。n=0时输入结束

    样例输入:
    4
    1 3 5 5
    1 1 2 3
    4 3 3 5
    6 5 5 1
    6 1 3 5
    1 3 5 5
    0 0 0 0
    10
    1 2 2 2 4 5 6 6 6 9
    1 2 3 4 5 6 7 8 9 1
    1 1 2 2 3 3 4 4 5 5
    1 2 1 3 1 5 1 6 1 9
    1 2 2 5 5 5 6 6 6 7
    0 0 0 0 0 0 0 0 0 0
    0
    样例输出:
    Game 1:

    (1,1)

    (2,0)

    (1,2)

    (1,2)

    (4,0)

    Game 2:

    (2,4)

    (3,2)

    (5,0)

    (7,0)

    分析:统计a[i]和b[i]  所有具有相同元素的个数  -   元素相同位置也相同的元素个数(A)  =   两个数组中元素相同位置不相同的个数(B)

     【有多少数字位置正确 (A),有多少数字在两个序列都出现过但位置不对(B)】

    #include<stdio.h>
    #define maxn 1010
    int main() {
          int n, a[maxn], b[maxn];
            int kase = 0;
            while(scanf("%d", &n) == 1 && n) {
                    //n=0时输入结束
                    printf("Game %d:
    ", ++kase);
                    for(int i = 0; i < n; i++)
                        scanf("%d", &a[i]);
                    for(;;) {
                        int A = 0, B = 0;
                        for(int i = 0; i < n; i++) {
                                    scanf("%d", &b[i]);
                                    if(a[i] == b[i])
                                        A++;
                        }
                        if(b[0] == 0)
                            break; //正常的猜测序列不会有0,所以只判断第一个数是否为0即可
                        for(int d = 1; d <= 9; d++) {
                                int c1 = 0, c2 = 0; //统计数字d在答案序列和猜测序列中各出现多少次
                                for(int i = 0; i < n; i++) {
                                        if(a[i] == d) c1++;
                                        if(b[i] == d) c2++;
                                }
                        if(c1 < c2)   //统计的最小的个数 即为序列拥有相同的元素的个数
                            B += c1;
                        else B += c2;
                        }
                        printf("    (%d,%d)
    ", A, B-A);
                    }
    
        }
        return 0;
    
    }

     例题3-5 生成元

    如果x加上x的各个数字之和得到y,就说x是y的生成元。给出n(1≤n≤100000),求最小
    生成元。无解输出0。例如,n=216,121,2005时的解分别为198,0,1979。

    分析思路:

    假设所求生成元为m。不难发现m<n。换句话说,只需枚举所有的m<n,看看有没有哪个数是n的生成元。可惜这样做的效率并不高,因为每次计算一个n的生成元都需要枚举n-1个数。

    只需一次性枚举100000内的所有正整数m,标记“m加上m的各个数字之和得到的数有一个生成元是m”,最后查表即可

    #include<stdio.h>
    #include<string.h>
    #define maxn 100005
    int ans[maxn];
    
    int main() {
        int T, n;
        memset(ans, 0, sizeof(ans));
        for(int m = 1; m < maxn; m++) {
            int x = m, y = m;
            while(x > 0) {
                    y += x % 10;
                    x /= 10;
            }
            // y 就是 m + m上的各个位的数字之和
            if(ans[y] == 0 || m < ans[y])  //如果还没填(ans[y] = 0)或者 m比填入的值还要小
                ans[y] = m;
        }
        scanf("%d", &T);//几组数据
        while(T--) {
            scanf("%d", &n);
            printf("%d
    ", ans[n]);
        }
        return 0;
    }

     例题3-6 

    环状序列长度为n的环状串有n种表示法,分别为从某个位置开始顺时针得到。例如,图3-4的环状串有10种表示:

     CGAGTCAGCT,GAGTCAGCTC,AGTCAGCTCG等。在这些表示法中,字典序最小的称为"最小表示"。输入一个长度为n(n≤100)的环状DNA串(只包含A、C、G、T这4种字符)的一种表示法,你的任务是输出该环状串的最小表示。例如,CTCC的最小表示是CCCT,CGAGTCAGCT的最小表示为AGCTCGAGTC。

    字典序,就是字符串在字典中的顺序。一般地,对于两个字符串,从第一个字符开始比较,当某一个位置的字符不同时,该位置字符较小的串字典序较小(例如,abc比bcd小);如果其中一个字符串已经没有更多字符,但另一个字符串还没结束,则较短的字符串的字典序较小(例如,hi比history小)。字典序的概念可以推广到任意序列,例如,序列1, 2, 4, 7比1, 2, 5小

    #include<stdio.h>
    #include<string.h>
    #define manx 105
    
    //比较 环状串S的表示法p是否比表示法ans的字典序小【长度是一样的,所以比较每个字典序的字符大小】
    int less(const char* s,int p,int ans){
        int n = strlen(s);
        for(int i =0;i < n;i++){
            if(s[(p+i)%n] != s[(ans+i)%n])
                return s[(p+i)%n] < s[(ans+i)%n];
        }
        return 0;
    
    }
        //假设输入的序列式 CGATCAGCT 第一次传入的是p=1,ans = 0,则比较
        //p表示法:CGATCATCT  <?> ans 表示法:GATCATCT的字典序大小
        //显然,第一位就不同,返回p表示法更小,即true
        //另ans = 1,始终使FLAG ans指向最小字典序的起始位置
    
    
    int main(){
        int T;
        char s[manx];
        scanf("%d",&T);
        while(T--){
            scanf("%s",s);
            int ans = 0;//变量ans表示目前为止,字典序最小串在输入串中的起始位置,即[最小字符]
            int n = strlen(s);//即,找一个最小字典序的起始位置!
            for(int i = 1;i <n;i++)
                if(less(s,i,ans))
                    ans = i;
            for(int i = 0;i<n;i++)
                putchar(s[(i+ans) %n]);
            putchar('
    ');
        }
        return 0;
    }
  • 相关阅读:
    TensorFlow从0到1之TensorFlow实现多元线性回归(11)
    TensorFlow从0到1之TensorFlow实现简单线性回归(10)
    TensorFlow从0到1之TensorFlow csv文件读取数据(9)
    TensorFlow从0到1之TensorFlow优化器(8)
    TensorFlow从0到1之TensorFlow损失函数(7)
    TensorFlow从0到1之回归算法(6)
    Python爬虫小白入门(六)爬取披头士乐队历年专辑封面-网易云音乐
    Python爬虫小白入门(五)PhatomJS+Selenium第二篇
    Python爬虫小白入门(四)PhatomJS+Selenium第一篇
    Python爬虫小白入门(三)BeautifulSoup库
  • 原文地址:https://www.cnblogs.com/expedition/p/11485330.html
Copyright © 2011-2022 走看看