iT邦幫忙

2021 iThome 鐵人賽

DAY 24
0
自我挑戰組

用 C & C++ 帶你手把手解 UVa 一顆星選集系列 第 24

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;
    }
    

上一篇
Day 0x17 UVa10252 Common Permutation
下一篇
Day 0x19 UVa10929 You can say 11
系列文
用 C & C++ 帶你手把手解 UVa 一顆星選集30

尚未有邦友留言

立即登入留言