Day 0x18 UVa10415 Eb Alto Saxophone Player

题意

  • 输入一连串音名,输出各手指按下的次数
  • 需要注意的有:
    1. 第一行输入整数 t 代表测资数
    2. 每笔测资输入歌曲的一连串音名,有可能为空
    3. 萨克斯风指法
      • 八个音名,十根手指
      • 大写代表高八度
      c: finger 2∼4, 7∼10
      d: finger 2∼4, 7∼9
      e: finger 2∼4, 7, 8
      f: finger 2∼4, 7
      g: finger 2∼4
      a: finger 2, 3
      b: finger 2
      C: finger 3
      D: finger 1∼4, 7∼9
      E: finger 1∼4, 7, 8
      F: finger 1∼4, 7
      G: finger 1∼4
      A: finger 1∼3
      B: finger 1∼2
      
    4. 若没用到就会放开,反之则持续按住

解法

  • 先读入测资数,再用 while 回圈重复读入每笔测资的音名;会有 getchar() 是因为 gets() 会吃到输入测资数後的换行
    int Case;
    
    scanf("%d", &Case);
    getchar();
    
    while(Case--){
    
        char Note[201] = {0};
    
        gets(Note);
        ...
    }
    
  • 宣告两字元阵列 current & next,分别代表当前有按下的手指与下个音要按下的手指,接着 for 回圈逐字元检查,观察各音名与对应的指法後可发现,手指刚好是由多到少且照顺序 (因为柱体越长音越低?),因此透过 switch 的特性,故意不要 break,若是小写就用 if 把 1 (也就是 [0]) 放开即可
    char current[11] = "0000000000";
    
    for(i = 0; i < strlen(Note); i++){
        char next[11] = "0000000000";
        switch(Note[i]){
            case'c':
                next[9] = '1';
            case'd':
            case'D':
                next[8] = '1';
            case'e':
            case'E':
                next[7] = '1';
            case'f':
            case'F':
                next[6] = '1';
            case'g':
            case'G':
                next[3] = '1';
            case'a':
            case'A':
                next[2] = '1';
            case'b':
            case'B':
                next[1] = '1';
                if(Note[i] >= 'A' && Note[i] <= 'G'){
                   next[0] = '1';
                }
                break;
            case'C':
                next[2] = '1';
        }
        ...
    }
    
  • 比较两字元阵列,计算新按下的有多少,最後更新当前按下的状态
    for(j = 0; j < 10; j++){
        if(current[j] == '0' && next[j] == '1'){
            count[j]++;
        }
    }
    strcpy(current, next);
    
  • C code ver. 1
    #include<stdio.h>
    #include<string.h>
    
    int main(){
    
        int Case;
        int i, j;
    
        scanf("%d", &Case);
        getchar();
    
        while(Case--){
    
            char Note[201] = {0};
            char current[11] = "0000000000";
            int count[10] = {0};
    
            gets(Note);
    
            for(i = 0; i < strlen(Note); i++){
                char next[11] = "0000000000";
                switch(Note[i]){
                    case'c':
                        next[9] = '1';
                    case'd':
                    case'D':
                        next[8] = '1';
                    case'e':
                    case'E':
                        next[7] = '1';
                    case'f':
                    case'F':
                        next[6] = '1';
                    case'g':
                    case'G':
                        next[3] = '1';
                    case'a':
                    case'A':
                        next[2] = '1';
                    case'b':
                    case'B':
                        next[1] = '1';
                        if(Note[i] >= 'A' && Note[i] <= 'G'){
                           next[0] = '1';
                        }
                        break;
                    case'C':
                        next[2] = '1';
                }
    
                for(j = 0; j < 10; j++){
                    if(current[j] == '0' && next[j] == '1'){
                        count[j]++;
                    }
                }
                strcpy(current, next);
            }
    
            printf("%d", count[0]);
            for(j = 1; j < 10; j++){
                printf(" %d", count[j]);
            }
            printf("\n");
        }
    
        return 0;
    }
    
  • 用建表法创建好各音名对应的指法
    char fingering[14][12] = {  "c0111001111", "d0111001110",
                                "e0111001100", "f0111001000",
                                "g0111000000", "a0110000000",
                                "b0100000000", "C0010000000",
                                "D1111001110", "E1111001100",
                                "F1111001000", "G1111000000",
                                "A1110000000", "B1100000000"};
    
  • 一样的概念,先 for 回圈逐字扫,再用内层 for 检查是哪个音名,用 if 判断第一个字元 (音名存在 [0]),找到就更新即将按下的指法,第二个 for 回圈计算新按下的次数
    for(i = 0; i < strlen(Note); i++){
        char next[12] = {0};
        for(j = 0; j < 14; j++){
            if(Note[i] == fingering[j][0]){
                strcpy(next, fingering[j]);
                break;
            }
        }
    
        for(j = 1; j <= 10; j++){
            if(current[j] == '0' && next[j] == '1'){
                count[j - 1]++;
            }
        }
        strcpy(current, next);
    }
    
  • C code ver. 2
    #include<stdio.h>
    #include<string.h>
    
    char fingering[14][12] = {  "c0111001111", "d0111001110",
                                "e0111001100", "f0111001000",
                                "g0111000000", "a0110000000",
                                "b0100000000", "C0010000000",
                                "D1111001110", "E1111001100",
                                "F1111001000", "G1111000000",
                                "A1110000000", "B1100000000"};
    
    int main(){
    
        int Case;
        int i, j;
    
        scanf("%d", &Case);
        getchar();
    
        while(Case--){
    
            char Note[201] = {0};
            char current[12] = "00000000000";
            int count[10] = {0};
    
            gets(Note);
    
            for(i = 0; i < strlen(Note); i++){
                char next[12] = {0};
                for(j = 0; j < 14; j++){
                    if(Note[i] == fingering[j][0]){
                        strcpy(next, fingering[j]);
                        break;
                    }
                }
    
                for(j = 1; j <= 10; j++){
                    if(current[j] == '0' && next[j] == '1'){
                        count[j - 1]++;
                    }
                }
                strcpy(current, next);
            }
    
            printf("%d", count[0]);
            for(j = 1; j < 10; j++){
                printf(" %d", count[j]);
            }
            printf("\n");
        }
    
        return 0;
    }
    

<<:  11 发动回转卡!

>>:  Day 07- Blocks

Day30-亲爱的,你成就了我

嗨,各位 经过了30天,最後一天让我说些感言ㄅ 首先我得先检讨一下自己 到後面都在打水仗啦rrrrr...

近似最短路径 (5)

11.5 Agarwal-Godfrey 的 2 倍近似 Distance Oracle Thoru...

大共享时代系列_006_简报协作

简报 ≠ PowerPoint 关於 Presentation program,其实还有其他的玩法~...

Swift 新手-打造第一个 iOS App

开发前的新手纠结 商学院出身,非资工背景,团队内也没有熟悉 app 开发的人才 决定做 app 接触...

Day 30 整体心得及未来规划

前言 今天来说一说今年参加的心得 以及铁人赛之後的规划 心得 铁人赛两年前有参加过一次 但今年很不一...