團體程式設計天梯賽-練習集L1-041~L1-050
技術標籤:團體程式設計天梯賽-練習集PTA演算法團體程式設計天梯賽
文章目錄
- L1-041. 尋找250
- L1-042. 日期格式化
- L1-043 閱覽室
- L1-044. 穩贏
- L1-045
- L1-046. 整除光棍
- L1-047. 裝睡
- L1-048. 矩陣A乘以B
- L1-049
- L1-050. 倒數第N個字串
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有Ra行、Ca列,B有Rb行、Cb列,則只有Ca與Rb相等時,兩個矩陣才能相乘。
輸入格式:
輸入先後給出兩個矩陣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(≤105)。
輸出格式:
在一行中輸出對應序列倒數第 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;
}
一定要自己寫一遍哦~~~