1. 程式人生 > 其它 >團體程式設計天梯賽-練習集L1-041~L1-050

團體程式設計天梯賽-練習集L1-041~L1-050

技術標籤:團體程式設計天梯賽-練習集PTA演算法團體程式設計天梯賽

文章目錄

L1-041. 尋找250

在這裡插入圖片描述

對方不想和你說話,並向你扔了一串數…… 而你必須從這一串數字中找到“250”這個高大上的感人數字。

輸入格式:
輸入在一行中給出不知道多少個絕對值不超過1000的整數,其中保證至少存在一個“250”。

輸出格式:
在一行中輸出第一次出現的“250”是對方扔過來的第幾個數字(計數從1開始)。題目保證輸出的數字在整型範圍內。

輸入樣例:
888 666 123 -233 250 13 250 -222

輸出樣例:
5

Note:
騷年,在這麼多對數字中找到你自己,其實還真不容易哈。這一題比較簡單,但是提一個小知識點,當你用 %d 來輸出一個字元時,輸出的是它的 ASCII 值,但如果你用 %d 來接受它,它就強制轉換成了數字了,當然這隻適用於單個字元的情況。這一題不用考慮那麼多,直接懟就是了。不要用字串來接受,那樣做會很麻煩,scanf 語句有空格識別的。你們可以注意到我的 count 是放在 while 的判斷裡的,這不是炫技,因為我試過單獨列一個 count++,發現佔用的執行記憶體比我現在的方法要大上幾百 KB,這強迫症哪裡能忍啊,果斷改掉!

#include <stdio.h>

int main()
{
    int n, count = 0;
    while (++count) {            // count 放在 while 迴圈內,自增之後永遠為增
        scanf("%d", &n);
        if (n == 250) {
            printf("%d", count);
            break;
        }
    }
    return 0;
}

讀字元還是要讀字元的,我不過寫出來給你們參考一下而已(真香)。

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main()
{
    char ch;
    int count = 0, num = 0;
    ch = getchar();
    while (ch != '\n') {
        if(isdigit(ch)) {               // 求數字大小
            ch = ch -'0';
            num = num*10 + ch;
        }
        if (num == 250) {               // 找到250,輸出計數,退出迴圈
            count ++;
            printf("%d", count);
            break;
        }
        if (ch == ' ') {
            // printf("num:%d count:%d\n", num, count);
            num = 0;                    // 遇見空格,重置 num 的值,同時計數加一
            count ++;
        }
        ch = getchar();                 // 讀取下一個字元
    }
    return 0;
}

L1-042. 日期格式化

世界上不同國家有不同的寫日期的習慣。比如美國人習慣寫成“月-日-年”,而中國人習慣寫成“年-月-日”。下面請你寫個程式,自動把讀入的美國格式的日期改寫成中國習慣的日期。

輸入格式:
輸入在一行中按照“mm-dd-yyyy”的格式給出月、日、年。題目保證給出的日期是1900年元旦至今合法的日期。

輸出格式:
在一行中按照“yyyy-mm-dd”的格式給出年、月、日。

輸入樣例:
03-15-2017

輸出樣例:
2017-03-15

Note:
之所以說 PTA 的題目好,是因為每一題看似都不難,但是想要最優是需要你去仔細思考的,本題就需要利用 scanf 函式的特性達到最優效果。

#include<stdio.h>

int main()
{
    int a, b, c;
    scanf("%d-%d-%d", &a, &b, &c);
    printf("%d-%02d-%02d\n", c, a, b);
    return 0;
}

L1-043 閱覽室

天梯圖書閱覽室請你編寫一個簡單的圖書借閱統計程式。當讀者借書時,管理員輸入書號並按下S鍵,程式開始計時;當讀者還書時,管理員輸入書號並按下E鍵,程式結束計時。書號為不超過1000的正整數。當管理員將0作為書號輸入時,表示一天工作結束,你的程式應輸出當天的讀者借書次數和平均閱讀時間。

注意:
由於線路偶爾會有故障,可能出現不完整的紀錄,即只有S沒有E,或者只有E沒有S的紀錄,系統應能自動忽略這種無效紀錄。另外,題目保證書號是書的唯一標識,同一本書在任何時間區間內只可能被一位讀者借閱。

輸入格式:
輸入在第一行給出一個正整數N(≤10),隨後給出N天的紀錄。每天的紀錄由若干次借閱操作組成,每次操作佔一行,格式為:

書號([1, 1000]內的整數) 鍵值(S或E) 發生時間(hh:mm,其中hh是[0,23]內的整數,mm是[0, 59]內整數)

每一天的紀錄保證按時間遞增的順序給出。

輸出格式:
對每天的紀錄,在一行中輸出當天的讀者借書次數和平均閱讀時間(以分鐘為單位的精確到個位的整數時間)。

輸入樣例:
3
1 S 08:10
2 S 08:35
1 E 10:00
2 E 13:16
0 S 17:00
0 S 17:00
3 E 08:10
1 S 08:20
2 S 09:00
1 E 09:20
0 E 17:00

輸出樣例:
2 196
0 0
1 60

Note:
本題有三個坑點,別問我我怎麼知道的,我也是搜別人部落格才知道的。。。第一個就是借閱時間只算最後一次借出到最早一次歸還,第二個就是結果要四捨五入的輸出。另外做題過程中自己發現的一些小問題,float 不能進行 ++ 操作,所以 count 要定義成 int 型別;四捨五入那裡 int 要加括號。而且要注意這題有一個測試案例是有00:00借書的,即 time 的值為0所以我選擇初始化陣列的值為-1,但正常情況下誰會00:00來借書啊。。。算是一個 bug吧。

memset 是對較大的陣列或結構體進行清零初始化的最快方法,因為它是直接對記憶體進行操作的。字串陣列就可以用 ‘\0’ 來初始化,雖然引數 c 要求是一個整數,但是整型和字元型是互通的。由於賦值為 ‘\0’ 和 0 是等價的,因此字元 ‘\0’ 在記憶體中就是 0。所以在 memset 中初始化為 0 也具有結束標誌符 ‘\0’ 的作用,所以通常我們就寫“0”。

#include <stdio.h>
#include <string.h>

int main()
{
    int N, num, count;
    float hh, mm, alltime, time[1000];
    char s[0];                                                      // 定義字串陣列來接收管理員的按鍵操作

    scanf("%d", &N);
    while (N--) {
        count = alltime = 0;                                        // 後一天,所有資料初始化
        memset(time, -1, sizeof(time));                             // 清空數組裡的殘餘值,也算初始化
        while (1) {
            scanf("%d%s %f:%f", &num, s, &hh, &mm);                 // 字串陣列會忽視前面的空格
            if (num == 0) break;
            else if (s[0] == 'S')
                time[num] = hh*60 + mm;                             // 第二次借書的時間可以覆蓋前一次
            else if (s[0] == 'E' && time[num] >= 0) {
                    alltime += (hh*60 + mm - time[num]);            // 借閱時間增加
                    count ++;                                       // 借出的書到換回來一個過程才算一次借閱
                    time[num] = -1;                                 // 置0標記已經歸還過,不能更新歸還時間
            }
        }

        if (count)
            printf("%d %d\n", count, (int)(alltime/count + 0.5));   // 輸出結果,平均借閱時間四捨五入輸出
        else
            printf("0 0\n");
    }
}

L1-044. 穩贏

大家應該都會玩“錘子剪刀布”的遊戲:兩人同時給出手勢,勝負規則如圖所示:
在這裡插入圖片描述
現要求你編寫一個穩贏不輸的程式,根據對方的出招,給出對應的贏招。但是!為了不讓對方輸得太慘,你需要每隔K次就讓一個平局。

輸入格式:
輸入首先在第一行給出正整數K(≤10),即平局間隔的次數。隨後每行給出對方的一次出招:ChuiZi代表“錘子”、JianDao代表“剪刀”、Bu代表“布”。End代表輸入結束,這一行不要作為出招處理。

輸出格式:
對每一個輸入的出招,按要求輸出穩贏或平局的招式。每招佔一行。

輸入樣例:
2
ChuiZi
JianDao
Bu
JianDao
Bu
ChuiZi
ChuiZi
End

輸出樣例:
Bu
ChuiZi
Bu
ChuiZi
JianDao
ChuiZi
Bu

Note:
間隔 n 次,則從一次平局到下一次平局需要加 n + 1。不能用 gets() 的原因在於 scanf 以回車或空格結束,然後將操作存入緩衝區,用 gets() 就會接收到結束符從而出錯。也可以在 k 輸入後加一個 getchar() 接受回車,然後後面全部用 get(s) 來接受字串,也不會產生這種問題。

#include<stdio.h>

int main()
{
    // 邊讀取字串邊輸出結果,同時計數,計數到了輸出一次平局,然後計數置0
    char s[8];
    int k, i = 0;                   // i 用於計數
    scanf("%d", &k);
    scanf("%s", s);                 // 不能用 gets(),否則會把回車讀進去
    while (s[0] != 'E') {
        i ++;                       // i 至少為1,否則第一局就是平局
        if ((s[0] == 'B' && i%(k + 1) != 0) || (s[0] == 'J' && i%(k + 1) == 0)) printf("JianDao\n");
        if ((s[0] == 'J' && i%(k + 1) != 0) || (s[0] == 'C' && i%(k + 1) == 0)) printf("ChuiZi\n");
        if ((s[0] == 'C' && i%(k + 1) != 0) || (s[0] == 'B' && i%(k + 1) == 0)) printf("Bu\n");
        scanf("%s", s);             // 讀取下一次出招
        if (i%(k + 1) == 0) i = 0;  // 到達間隔,計數置0
    }
    return 0;
}

L1-045


L1-046. 整除光棍

這裡所謂的“光棍”,並不是指單身汪啦~ 說的是全部由1組成的數字,比如1、11、111、1111等。傳說任何一個光棍都能被一個不以5結尾的奇數整除。比如,111111就可以被13整除。 現在,你的程式要讀入一個整數x,這個整數一定是奇數並且不以5結尾。然後,經過計算,輸出兩個數字:第一個數字s,表示x乘以s是一個光棍,第二個數字n是這個光棍的位數。這樣的解當然不是唯一的,題目要求你輸出最小的解。

提示:
一個顯然的辦法是逐漸增加光棍的位數,直到可以整除x為止。但難點在於,s可能是個非常大的數 —— 比如,程式輸入31,那麼就輸出3584229390681和15,因為31乘以3584229390681的結果是111111111111111,一共15個1。

輸入格式:
輸入在一行中給出一個不以5結尾的正奇數x(<1000)。

輸出格式:
在一行中輸出相應的最小的s和n,其間以1個空格分隔。

輸入樣例:
31

輸出樣例:
3584229390681 15

Note:
結果太大了,所以不可能正常的讓機器去真計算,所以要寫一個演算法來模擬除法運算的過程。一開始我定義了一個很大字元陣列來接收運算中的商,然後絞盡腦汁兒想了很久怎麼把把商存入字元陣列,腦袋痛就睡著了。夢中驚醒,我真是太 sd 了,我為什麼要存入陣列呀?直接輸出不就行了嗎。。。腦子抽的我真不適合學程式設計啊。而且題目中也沒有暗示用字元陣列來儲存運算過程中的商,所以千萬不要再像我一樣動不動就字元陣列了。。。第一個 while 迴圈那裡,不要令 x >= s,因為輸入的數 x 有可能本身就是一個光棍,此時商就是1,位數就是 x 的位數。但是因為 s 自增會變成 x 一樣大,因為迴圈為真的原因還會自增一次,就導致結果錯誤了。

#include <stdio.h>

int main()
{
    int x, s = 0, n = 0;                            // s 記錄餘數,n 用來記錄位數
    scanf("%d", &x);
    if (x%5 == 0 || x%2 == 0 || x >= 1000) return 0;// 無效輸入退出程式

    while (x > s) {                                 // s 小於 x,則補1自增直到大於 x
        s = s*10 + 1;
        n ++;                                       // 同時位數自增
    }

    while(1) {
        printf("%d", s/x);                          // 計算商並輸出
        s  = s%x;                                   // 令 s 等於餘數
        if (s == 0) break;                          // 餘數為0,退出迴圈
        s = s*10 + 1;                               // 除法的規則,s 只需要自增一位肯定大於 x
        n ++;                                       // 位數加一
    }
    printf(" %d", n);                               // 輸出位數,別忘記空格
    return 0;
}

L1-047. 裝睡

你永遠叫不醒一個裝睡的人 —— 但是通過分析一個人的呼吸頻率和脈搏,你可以發現誰在裝睡!醫生告訴我們,正常人睡眠時的呼吸頻率是每分鐘15-20次,脈搏是每分鐘50-70次。下面給定一系列人的呼吸頻率與脈搏,請你找出他們中間有可能在裝睡的人,即至少一項指標不在正常範圍內的人。

輸入格式:
輸入在第一行給出一個正整數N(≤10)。隨後N行,每行給出一個人的名字(僅由英文字母組成的、長度不超過3個字元的串)、其呼吸頻率和脈搏(均為不超過100的正整數)。

輸出格式:
按照輸入順序檢查每個人,如果其至少一項指標不在正常範圍內,則輸出其名字,每個名字佔一行。

輸入樣例:
4
Amy 15 70
Tom 14 60
Joe 18 50
Zoe 21 71

輸出樣例:
Tom
Zoe

Note:
唉我真是淨挑些簡單的題目做。。。沒什麼好記錄的。

#include <stdio.h>
#include <string.h>

int main()
{
    int i, n, flag;
    char name[4];
    int br, pl;
    scanf("%d", &n);
    for (i = 0; i < n; i++) {
        flag = 0;
        scanf("%s %d %d", name, &br, &pl);
        if (br < 15 || br > 20) flag = 1;
        if (pl < 50 || pl > 70) flag = 1;
        if (flag) printf("%s\n", name);
        memset(name, '\0', sizeof(name));
    }
    return 0;
}

哈哈哈哈哈哈哈你要是不往下面看你就吃虧拉,其實這題更簡單的做法是下面這樣的,甚至都不要清空陣列哈哈哈。直接用逆否做就行啦,我們知道呼吸15到20之間且脈搏50到70之間就不算睡覺,它的逆否就是非呼吸15到20之間或脈搏50到70之間。用該逆否做 if 的判斷就可以啦。

#include <stdio.h>

int main()
{
    int i, n, br, pl;
    char name[4];
    scanf("%d", &n);
    for (i = 0; i < n; i++) {
        scanf("%s %d %d", name, &br, &pl);
        if (!(br <= 20 && br >= 15)||!(pl <= 70 && pl >= 50))
            printf("%s\n", name);
    }
    return 0;
}

L1-048. 矩陣A乘以B

給定兩個矩陣A和B,要求你計算它們的乘積矩陣AB。需要注意的是,只有規模匹配的矩陣才可以相乘。即若A有R​a​​行、C​a​​列,B有R​b​​行、C​b​​列,則只有C​a​​與R​b​​相等時,兩個矩陣才能相乘。

輸入格式:
輸入先後給出兩個矩陣A和B。對於每個矩陣,首先在一行中給出其行數R和列數C,隨後R行,每行給出C個整數,以1個空格分隔,且行首尾沒有多餘的空格。輸入保證兩個矩陣的R和C都是正數,並且所有整數的絕對值不超過100。

輸出格式:
若輸入的兩個矩陣的規模是匹配的,則按照輸入的格式輸出乘積矩陣AB,否則輸出Error: Ca != Rb,其中Ca是A的列數,Rb是B的行數。

輸入樣例1:
2 3
1 2 3
4 5 6
3 4
7 8 9 0
-1 -2 -3 -4
5 6 7 8

輸出樣例1:
2 4
20 22 24 16
53 58 63 28

輸入樣例2:
3 2
38 26
43 -5
0 17
3 2
-11 57
99 68
81 72

輸出樣例2:
Error: 2 != 3

Note:
做完之後一直有兩個測試過不去,除錯了很久發現二維陣列用的 char 定義,用字串習慣了。。。

#include <stdio.h>

int main()
{
    // 二維陣列剛好可以表示矩陣,一維表示行號,二維表示列號,因此矩陣題目二維矩陣是最好的
    int ra, ca, rb, cb, i, j, k;            //定義 A,B 矩陣的行值列值
    int A[100][100], B[100][100], C[100][100] = {0};

    scanf("%d%d", &ra, &ca);                // 輸入不一定非要空格的,scanf 能識別
    for (i = 0; i < ra; i++)
        for (j = 0; j < ca; j++)
            scanf("%d", &A[i][j]);

    scanf("%d%d", &rb, &cb);
    for (i = 0; i < rb; i++)
        for (j = 0; j < cb; j++)
            scanf("%d", &B[i][j]);

    if (ca != rb) {                         // 不能進行矩陣乘法
        printf("Error: %d != %d", ca, rb);
        return 0;
    }
    printf("%d %d\n", ra, cb);
    for (i = 0; i < ra; i++) {              // 先行
        for (j = 0; j < cb; j++) {          // 後列
            for (k = 0; k < ca; k++)        // 行列式乘法規律,中間數增到 ca - 1 為止
                C[i][j] += A[i][k]*B[k][j]; // 計算 C 的每一項
            printf("%d", C[i][j]);
            if (j + 1 != cb) printf(" ");   // 輸出空格
        }
        if (i + 1 != ra) printf("\n");      // 換行
    }
    return 0;
}

L1-049


L1-050. 倒數第N個字串

給定一個完全由小寫英文字母組成的字串等差遞增序列,該序列中的每個字串的長度固定為 L,從 L 個 a 開始,以 1 為步長遞增。例如當 L 為 3 時,序列為 { aaa, aab, aac, …, aaz, aba, abb, …, abz, …, zzz }。這個序列的倒數第27個字串就是 zyz。對於任意給定的 L,本題要求你給出對應序列倒數第 N 個字串。

輸入格式:
輸入在一行中給出兩個正整數 L(2 ≤ L ≤ 6)和 N(≤10​5​​)。

輸出格式:
在一行中輸出對應序列倒數第 N 個字串。題目保證這個字串是存在的。

輸入樣例:
3 7417

輸出樣例:
pat

Note:
直接令一個整型資料等於double型別資料的計算結果會丟失精讀,不準確。在用 z 來表示偏移的字母時,理論上是偏移多少減多少。這一題要求的是倒數,比如那一位應該是 x,則 z 的 ASCII 值應該減去2,但實際上 x 是倒數第3位,所以在輸入的 N 應該要處理完,即先減去1後才能得到正確的倒數位的字母。

#include <stdio.h>
#include <math.h>
double main()
{
    double L, N, n, yu, digit;
    scanf("%lf %lf", &L, &N);
    n = L - 1;                          // n 題目保證字串是存在的
    N = N - 1;                          // 即 N 肯定是小於 pow(26, n),所以直接從 n - 1算

    while (1) {
        digit = floor(N/(pow(26, n)));  // 將整數商部分存入 digit,即為對應為的位置偏移,同時要向下取整
        char b = 'z';                   // 這裡是將字元 b 賦值字元 z,寫在表示式裡的 'z' 是 z 的 ASCII 碼值
        printf("%c", b - (int)digit);   // ASCII碼的得轉換是整型運算
        yu = pow(26, n);                // 如果在這裡用 int 定義 yu 會丟失精度產生計算偏差
        N = (int)N%(int)yu;             // % 兩邊必須是整型變數
        n --;                           // 注意 n = 0 是要參與運算的,所以判定是 n 是否小於0
        if (n < 0) break;
    }
    return 0;
}

一定要自己寫一遍哦~~~