[0]zero-index clytie0x/zero-index

11.5 แบบฝึกหัด

เขียนแต่ละข้อเป็นไฟล์ใหม่ใน Code::Blocks รันแล้วเทียบกับผลลัพธ์ที่ต้องได้ให้ตรงทุกตัวอักษร รวมถึงช่องว่างและการขึ้นบรรทัด ติดจริงๆ ค่อยเปิดคำใบ้ และเปิดเฉลยหลังทำเสร็จแล้วเท่านั้น

ข้อ 1 ใครได้รางวัล

ระดับง่าย เวลาไม่เกิน 1 วินาที

ห้องเรียนมีนักเรียน N คน แต่ละคนมีชื่อและคะแนนสอบปลายภาค ครูจะมอบรางวัลให้คนที่ได้คะแนนสูงสุด ถ้ามีหลายคนได้คะแนนสูงสุดเท่ากัน รางวัลเป็นของคนที่ส่งข้อสอบก่อน ซึ่งก็คือคนที่อยู่ก่อนในข้อมูลเข้า ส่วนคนอื่นที่ได้คะแนนเท่ากันจะได้เกียรติบัตร ให้หาว่าใครได้รางวัล และมีนักเรียนกี่คนที่ได้คะแนนสูงสุด

ข้อมูลเข้า

บรรทัดแรกมีจำนวนเต็ม N โดยที่ 1 ≤ N ≤ 1000

อีก N บรรทัด แต่ละบรรทัดมีชื่อของนักเรียนหนึ่งคน และคะแนน S คั่นด้วยช่องว่าง ชื่อเป็นตัวอักษรภาษาอังกฤษยาว 1 ถึง 20 ตัว ไม่มีช่องว่าง และ 0 ≤ S ≤ 100 ชื่ออาจซ้ำกันได้

ข้อมูลออก

บรรทัดแรกพิมพ์ชื่อและคะแนนของคนที่ได้รางวัล คั่นด้วยช่องว่าง บรรทัดที่สองพิมพ์จำนวนนักเรียนที่ได้คะแนนสูงสุด รวมคนที่ได้รางวัลด้วย

5
Mali 87
Krit 92
Ploy 78
Nat 92
Beam 65
Krit 92
2
3
Somchai 45
Kanya 60
Somsak 59
Kanya 60
1
ดูคำใบ้

เก็บนักเรียนเป็นอาเรย์ของ struct แล้วหาคนคะแนนสูงสุดด้วยการจำ index ตามหน้า 11.2 ใช้ > ไม่ใช่ >= เพื่อให้ได้คนที่มาก่อน จากนั้นวนอีกรอบนับว่ามีกี่คนที่คะแนนเท่ากับคนนั้น

ดูเฉลย
#include <stdio.h>

typedef struct {
    char name[21];
    int score;
} Student;

Student students[1000];

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%s %d", students[i].name, &students[i].score);
    }
    int best = 0;
    for (int i = 1; i < n; i++) {
        if (students[i].score > students[best].score) {
            best = i;
        }
    }
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (students[i].score == students[best].score) {
            count++;
        }
    }
    printf("%s %d\n", students[best].name, students[best].score);
    printf("%d\n", count);
    return 0;
}

ข้อ 2 ลูกบอลในสนาม

ระดับง่าย เวลาไม่เกิน 1 วินาที

สนามฟุตซอลเป็นสี่เหลี่ยมผืนผ้าที่ด้านขนานกับแกน x และแกน y มุมซ้ายล่างอยู่ที่ (X1, Y1) มุมขวาบนอยู่ที่ (X2, Y2) หลังซ้อมเสร็จมีลูกบอลกระจายอยู่ N ลูก ลูกที่ i อยู่ที่ (x, y) โค้ชอยากรู้ว่ามีลูกบอลอยู่ในสนามกี่ลูก อยู่บนเส้นขอบสนามพอดีกี่ลูก และอยู่นอกสนามกี่ลูก ลูกบอลถือเป็นจุดหนึ่งจุด

ข้อมูลเข้า

บรรทัดแรกมีจำนวนเต็ม X1 Y1 X2 Y2 คั่นด้วยช่องว่าง โดยที่ X1 < X2 และ Y1 < Y2

บรรทัดที่สองมีจำนวนเต็ม N โดยที่ 1 ≤ N ≤ 1000

อีก N บรรทัด แต่ละบรรทัดมีจำนวนเต็ม x และ y ของลูกบอลหนึ่งลูก

พิกัดทุกตัวอยู่ระหว่าง -10000 ถึง 10000

ข้อมูลออก

บรรทัดเดียว มีจำนวนลูกที่อยู่ในสนาม จำนวนลูกที่อยู่บนเส้นขอบ และจำนวนลูกที่อยู่นอกสนาม คั่นด้วยช่องว่าง

0 0 10 6
6
3 2
10 4
12 3
0 0
5 6
7 7
1 3 2
-5 -3 5 3
3
0 0
-5 3
6 0
1 1 1
ดูคำใบ้

เก็บสนามเป็น Rect ที่มี Point สองมุมตามหน้า 11.3 แล้วเขียนฟังก์ชันรับสนามกับลูกบอลหนึ่งลูก คืนค่าว่าอยู่ข้างใน บนเส้น หรือข้างนอก ตรวจข้างนอกก่อน ถ้าไม่อยู่ข้างนอก แล้วพิกัดตัวใดตัวหนึ่งตรงกับขอบ ก็คือบนเส้น ระวังลูกที่ x ตรงกับเส้นข้างแต่ y สูงเกินสนาม ลูกนั้นอยู่ข้างนอก

ดูเฉลย
#include <stdio.h>

typedef struct {
    int x;
    int y;
} Point;

typedef struct {
    Point low;
    Point high;
} Rect;

int where(Rect field, Point ball)
{
    if (ball.x < field.low.x || ball.x > field.high.x || ball.y < field.low.y || ball.y > field.high.y) {
        return 2;
    }
    if (ball.x == field.low.x || ball.x == field.high.x || ball.y == field.low.y || ball.y == field.high.y) {
        return 1;
    }
    return 0;
}

int main()
{
    Rect field;
    scanf("%d %d %d %d", &field.low.x, &field.low.y, &field.high.x, &field.high.y);
    int n;
    scanf("%d", &n);
    int count[3] = {0, 0, 0};
    for (int i = 0; i < n; i++) {
        Point ball;
        scanf("%d %d", &ball.x, &ball.y);
        count[where(field, ball)]++;
    }
    printf("%d %d %d\n", count[0], count[1], count[2]);
    return 0;
}

ข้อ 3 ร้านที่ใกล้บ้านที่สุด

ระดับง่าย เวลาไม่เกิน 1 วินาที

บ้านของน้องอยู่ที่พิกัด (X, Y) รอบบ้านมีร้านสะดวกซื้อ N ร้าน แต่ละร้านมีชื่อและพิกัดของตัวเอง น้องอยากรู้ว่าร้านไหนอยู่ใกล้บ้านที่สุด เมื่อวัดระยะเป็นเส้นตรง ถ้ามีหลายร้านใกล้เท่ากัน ให้ตอบร้านที่อยู่ก่อนในข้อมูลเข้า

เพื่อไม่ต้องพิมพ์ทศนิยม ให้ตอบ กำลังสองของระยะทาง แทนระยะทาง ระหว่างจุด (x1, y1) กับ (x2, y2) คือ (x1 - x2)2 + (y1 - y2)2

ข้อมูลเข้า

บรรทัดแรกมีจำนวนเต็ม X Y คั่นด้วยช่องว่าง

บรรทัดที่สองมีจำนวนเต็ม N โดยที่ 1 ≤ N ≤ 1000

อีก N บรรทัด แต่ละบรรทัดมีชื่อร้าน และพิกัด x y ของร้าน คั่นด้วยช่องว่าง ชื่อร้านเป็นตัวอักษรภาษาอังกฤษหรือตัวเลขยาว 1 ถึง 20 ตัว ไม่มีช่องว่าง

พิกัดทุกตัวอยู่ระหว่าง -109 ถึง 109 ร้านอาจอยู่ที่เดียวกับบ้าน หรือที่เดียวกับร้านอื่นก็ได้

ข้อมูลออก

บรรทัดเดียว มีชื่อร้านที่ใกล้ที่สุด และกำลังสองของระยะทางจากบ้านถึงร้านนั้น คั่นด้วยช่องว่าง

2 3
3
SevenA 7 3
Lotus -1 6
Mart24 4 -2
Lotus 18
0 0
3
North 0 5
East 5 0
Corner 3 4
North 25
ดูคำใบ้

เทียบระยะทางด้วยกำลังสองของระยะทางแบบตัวอย่าง typedef ในหน้า 11.1 ไม่ต้องถอดราก เพราะระยะที่น้อยกว่าก็มีกำลังสองน้อยกว่าเสมอ พิกัดไกลกันได้ถึง 2 × 109 ซึ่งแค่ผลต่างก็เกือบเต็ม int แล้ว และกำลังสองใหญ่ถึง 8 × 1018 ให้เก็บพิกัดใน struct เป็น long long ตั้งแต่แรก

ดูเฉลย
#include <stdio.h>

typedef struct {
    long long x;
    long long y;
} Point;

typedef struct {
    char name[21];
    Point place;
} Shop;

Shop shops[1000];

long long distance_squared(Point a, Point b)
{
    long long dx = a.x - b.x;
    long long dy = a.y - b.y;
    return dx * dx + dy * dy;
}

int main()
{
    Point home;
    scanf("%lld %lld", &home.x, &home.y);
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%s %lld %lld", shops[i].name, &shops[i].place.x, &shops[i].place.y);
    }
    int best = 0;
    long long best_distance = distance_squared(home, shops[0].place);
    for (int i = 1; i < n; i++) {
        long long d = distance_squared(home, shops[i].place);
        if (d < best_distance) {
            best = i;
            best_distance = d;
        }
    }
    printf("%s %lld\n", shops[best].name, best_distance);
    return 0;
}

ข้อ 4 นักวิ่งที่เร็วที่สุด

ระดับกลาง เวลาไม่เกิน 1 วินาที

งานวิ่งการกุศลปล่อยตัวนักวิ่งเป็นกลุ่ม กลุ่มละเวลาไม่เท่ากัน เพื่อไม่ให้แออัดที่จุดเริ่ม ชิปที่ข้อเท้าของนักวิ่งแต่ละคนบันทึกเวลาออกตัวและเวลาเข้าเส้นชัยเป็นชั่วโมง นาที วินาที ผู้ชนะคือคนที่ ใช้เวลาวิ่งน้อยที่สุด ไม่ใช่คนที่เข้าเส้นก่อน ถ้ามีหลายคนใช้เวลาเท่ากัน ให้คนที่เข้าเส้นชัยก่อนชนะ ถ้ายังเท่ากันอีก ให้คนที่อยู่ก่อนในข้อมูลเข้าชนะ

ให้หาว่าใครชนะ และใช้เวลาวิ่งเท่าไร

ข้อมูลเข้า

บรรทัดแรกมีจำนวนเต็ม N โดยที่ 1 ≤ N ≤ 1000

อีก N บรรทัด แต่ละบรรทัดมีชื่อนักวิ่ง ตามด้วยจำนวนเต็มหกตัว คือชั่วโมง นาที วินาที ของเวลาออกตัว แล้วตามด้วยชั่วโมง นาที วินาที ของเวลาเข้าเส้นชัย ทุกอย่างคั่นด้วยช่องว่าง ชื่อเป็นตัวอักษรภาษาอังกฤษยาว 1 ถึง 20 ตัว ชั่วโมงอยู่ระหว่าง 0 ถึง 23 นาทีและวินาทีอยู่ระหว่าง 0 ถึง 59 ทุกคนวิ่งจบในวันเดียวกัน และเวลาเข้าเส้นชัยมาหลังเวลาออกตัวเสมอ

ข้อมูลออก

บรรทัดเดียว มีชื่อผู้ชนะ ตามด้วยเวลาที่ใช้เป็นชั่วโมง นาที และวินาที คั่นด้วยช่องว่าง นาทีและวินาทีต้องอยู่ระหว่าง 0 ถึง 59

3
Mali 6 0 0 6 50 0
Krit 6 30 0 7 15 0
Ploy 6 15 0 7 3 20
Krit 0 45 0
2
Nat 7 10 0 9 0 20
Beam 7 0 0 8 50 20
Beam 1 50 20
ดูคำใบ้

เก็บนักวิ่งเป็น struct ที่มีชื่อและ Time สองตัว แล้วใช้ to_seconds กับ from_seconds แบบหน้า 11.4 คนที่ชนะคือคนที่ใช้เวลาน้อยกว่า ถ้าใช้เวลาเท่ากันให้ดูว่าใครเข้าเส้นก่อน ซึ่งก็เทียบเวลาเข้าเส้นเป็นวินาทีได้เหมือนกัน ถ้าเท่ากันทั้งสองอย่าง ใช้ < ไม่ใช่ <= เพื่อให้ได้คนที่มาก่อน

ดูเฉลย
#include <stdio.h>

typedef struct {
    int hours;
    int minutes;
    int seconds;
} Time;

typedef struct {
    char name[21];
    Time start;
    Time finish;
} Runner;

Runner runners[1000];

int to_seconds(Time t)
{
    return t.hours * 3600 + t.minutes * 60 + t.seconds;
}

Time from_seconds(int total)
{
    Time t;
    t.hours = total / 3600;
    t.minutes = total % 3600 / 60;
    t.seconds = total % 60;
    return t;
}

int used(const Runner *r)
{
    return to_seconds(r->finish) - to_seconds(r->start);
}

int faster(const Runner *a, const Runner *b)
{
    if (used(a) != used(b)) {
        return used(a) < used(b);
    }
    return to_seconds(a->finish) < to_seconds(b->finish);
}

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        Runner *r = &runners[i];
        scanf("%s %d %d %d %d %d %d", r->name,
              &r->start.hours, &r->start.minutes, &r->start.seconds,
              &r->finish.hours, &r->finish.minutes, &r->finish.seconds);
    }
    int best = 0;
    for (int i = 1; i < n; i++) {
        if (faster(&runners[i], &runners[best])) {
            best = i;
        }
    }
    Time t = from_seconds(used(&runners[best]));
    printf("%s %d %d %d\n", runners[best].name, t.hours, t.minutes, t.seconds);
    return 0;
}

ข้อ 5 คลังสินค้า

ระดับกลาง เวลาไม่เกิน 1 วินาที

คลังสินค้าของร้านเครื่องเขียนมีสินค้า M ชนิด แต่ละชนิดมีรหัสไม่ซ้ำกัน จำนวนที่มีอยู่ในคลัง และราคาต่อชิ้น วันนี้มีคำสั่ง Q คำสั่งเข้ามาตามลำดับ คำสั่งมีสองแบบ

  • IN รหัส K รับสินค้ารหัสนั้นเข้าคลัง K ชิ้น
  • OUT รหัส K เบิกสินค้ารหัสนั้นออก K ชิ้น ถ้าในคลังมีน้อยกว่า K ชิ้น คำสั่งนี้ถูกปฏิเสธ ไม่มีการเบิกออกเลยแม้แต่ชิ้นเดียว

หลังทำครบทุกคำสั่ง ให้รายงานจำนวนคงเหลือของสินค้าทุกชนิด มูลค่ารวมของสินค้าทั้งคลัง คือผลรวมของจำนวนคงเหลือคูณราคาต่อชิ้นของทุกชนิด และจำนวนคำสั่งที่ถูกปฏิเสธ

ข้อมูลเข้า

บรรทัดแรกมีจำนวนเต็ม M และ Q โดยที่ 1 ≤ M ≤ 100 และ 1 ≤ Q ≤ 1000

อีก M บรรทัด แต่ละบรรทัดมีรหัสสินค้า จำนวนเริ่มต้น และราคาต่อชิ้น คั่นด้วยช่องว่าง รหัสเป็นตัวอักษรภาษาอังกฤษตัวพิมพ์ใหญ่หรือตัวเลข ยาว 1 ถึง 10 ตัว จำนวนเริ่มต้นอยู่ระหว่าง 0 ถึง 106 และราคาอยู่ระหว่าง 1 ถึง 106

อีก Q บรรทัด แต่ละบรรทัดเป็นคำสั่งหนึ่งคำสั่งตามรูปแบบข้างบน รหัสในคำสั่งมีอยู่ในคลังแน่นอน และ 1 ≤ K ≤ 106

ข้อมูลออก

M บรรทัดแรก พิมพ์รหัสและจำนวนคงเหลือของสินค้าแต่ละชนิด คั่นด้วยช่องว่าง เรียงตามลำดับในข้อมูลเข้า บรรทัดถัดไปพิมพ์มูลค่ารวมของสินค้าทั้งคลัง และบรรทัดสุดท้ายพิมพ์จำนวนคำสั่งที่ถูกปฏิเสธ

3 5
PEN01 50 12
ERASER 20 5
RULER30 0 25
OUT PEN01 30
OUT RULER30 1
IN RULER30 10
OUT PEN01 25
OUT ERASER 20
PEN01 20
ERASER 0
RULER30 10
490
2
1 2
A 5 100
IN A 3
OUT A 9
A 8
800
1
ดูคำใบ้

เก็บสินค้าเป็นอาเรย์ของ struct ที่มีรหัส จำนวน และราคา แล้วเขียนฟังก์ชันหาว่ารหัสนี้อยู่ช่องไหนด้วย strcmp แบบหน้า 11.2 อ่านชนิดคำสั่งด้วย %s แล้วเทียบกับ "IN" ระวังสองเรื่อง เบิกได้เมื่อของมีมากกว่าหรือเท่ากับที่ขอ และมูลค่าของสินค้าหนึ่งชนิดใหญ่ได้ถึงประมาณ 1015 ต้องแปลงเป็น long long ก่อนคูณ

ดูเฉลย
#include <stdio.h>
#include <string.h>

typedef struct {
    char code[11];
    int quantity;
    int price;
} Item;

Item items[100];

int find_item(const char code[], int m)
{
    for (int i = 0; i < m; i++) {
        if (strcmp(items[i].code, code) == 0) {
            return i;
        }
    }
    return -1;
}

int main()
{
    int m, q;
    scanf("%d %d", &m, &q);
    for (int i = 0; i < m; i++) {
        scanf("%s %d %d", items[i].code, &items[i].quantity, &items[i].price);
    }
    int rejected = 0;
    for (int k = 0; k < q; k++) {
        char type[4], code[11];
        int amount;
        scanf("%s %s %d", type, code, &amount);
        Item *item = &items[find_item(code, m)];
        if (strcmp(type, "IN") == 0) {
            item->quantity += amount;
        } else if (item->quantity >= amount) {
            item->quantity -= amount;
        } else {
            rejected++;
        }
    }
    long long total = 0;
    for (int i = 0; i < m; i++) {
        printf("%s %d\n", items[i].code, items[i].quantity);
        total += (long long)items[i].quantity * items[i].price;
    }
    printf("%lld\n", total);
    printf("%d\n", rejected);
    return 0;
}

ข้อ 6 พื้นที่ที่กล้องทุกตัวเห็น

ระดับกลาง เวลาไม่เกิน 1 วินาที

ลานจอดรถติดกล้องวงจรปิด N ตัว กล้องแต่ละตัวมองเห็นพื้นที่เป็นสี่เหลี่ยมผืนผ้าที่ด้านขนานกับแกน x และแกน y ช่างที่ติดตั้งจดพื้นที่ของกล้องแต่ละตัวไว้เป็นพิกัดของมุมสองมุมที่อยู่ตรงข้ามกัน แต่ไม่ได้จดว่ามุมไหนเป็นมุมไหน อาจเป็นมุมซ้ายล่างกับมุมขวาบน หรือมุมซ้ายบนกับมุมขวาล่าง และจดมุมไหนก่อนก็ได้

ฝ่ายรักษาความปลอดภัยอยากรู้ว่า พื้นที่ส่วนที่ กล้องทุกตัว มองเห็นพร้อมกันมีขนาดกี่ตารางหน่วย ถ้าไม่มีพื้นที่แบบนั้น หรือส่วนที่ทุกตัวเห็นเป็นแค่เส้นหรือจุด ให้ตอบ 0

ข้อมูลเข้า

บรรทัดแรกมีจำนวนเต็ม N โดยที่ 1 ≤ N ≤ 100000

อีก N บรรทัด แต่ละบรรทัดมีจำนวนเต็ม x1 y1 x2 y2 คั่นด้วยช่องว่าง หมายถึงกล้องตัวหนึ่งเห็นสี่เหลี่ยมที่มีมุมตรงข้ามกันอยู่ที่ (x1, y1) และ (x2, y2) รับประกันว่า x1 ≠ x2 และ y1 ≠ y2 พิกัดทุกตัวอยู่ระหว่าง -109 ถึง 109

ข้อมูลออก

พื้นที่ส่วนที่กล้องทุกตัวมองเห็น

2
0 0 6 4
3 1 8 5
9
3
10 10 2 3
0 8 7 0
5 12 1 4
12
ดูคำใบ้

เขียนฟังก์ชันรับมุมสองมุม แล้วคืน Rect ที่มี low เป็นมุมซ้ายล่างและ high เป็นมุมขวาบนจริงๆ ตามหน้า 11.4 จากนั้นใช้วิธีหาส่วนที่ทับกันในหน้า 11.3 กับกล้องทีละตัว ส่วนที่ทุกตัวเห็นมีขอบซ้ายเป็นค่ามากของขอบซ้ายทุกตัว และขอบขวาเป็นค่าน้อยของขอบขวาทุกตัว อย่าลืมกรณีที่ไม่ทับกันทั้งแนวนอนและแนวตั้งพร้อมกัน และพื้นที่ใหญ่ถึง 4 × 1018

ดูเฉลย
#include <stdio.h>

typedef struct {
    long long x;
    long long y;
} Point;

typedef struct {
    Point low;
    Point high;
} Rect;

long long min_ll(long long a, long long b)
{
    return a < b ? a : b;
}

long long max_ll(long long a, long long b)
{
    return a > b ? a : b;
}

Rect make_rect(Point a, Point b)
{
    Rect r;
    r.low.x = min_ll(a.x, b.x);
    r.low.y = min_ll(a.y, b.y);
    r.high.x = max_ll(a.x, b.x);
    r.high.y = max_ll(a.y, b.y);
    return r;
}

Rect read_rect()
{
    Point a, b;
    scanf("%lld %lld %lld %lld", &a.x, &a.y, &b.x, &b.y);
    return make_rect(a, b);
}

int main()
{
    int n;
    scanf("%d", &n);
    Rect common = read_rect();
    for (int i = 1; i < n; i++) {
        Rect r = read_rect();
        common.low.x = max_ll(common.low.x, r.low.x);
        common.low.y = max_ll(common.low.y, r.low.y);
        common.high.x = min_ll(common.high.x, r.high.x);
        common.high.y = min_ll(common.high.y, r.high.y);
    }
    long long width = common.high.x - common.low.x;
    long long height = common.high.y - common.low.y;
    if (width > 0 && height > 0) {
        printf("%lld\n", width * height);
    } else {
        printf("0\n");
    }
    return 0;
}

ข้อ 7 ตารางคะแนนลีก

ระดับยาก เวลาไม่เกิน 1 วินาที

ลีกฟุตบอลของโรงเรียนมี T ทีม ตลอดฤดูกาลแข่งไป M นัด ทีมสองทีมอาจเจอกันได้หลายครั้ง หรือไม่เจอกันเลยก็ได้ แต่ละนัดให้แต้มแบบนี้ ชนะได้ 3 แต้ม เสมอได้ 1 แต้ม แพ้ได้ 0 แต้ม

อันดับในตารางตัดสินตามเกณฑ์ต่อไปนี้ทีละข้อ ถ้าข้อก่อนหน้าเท่ากันจึงดูข้อถัดไป

  1. แต้มรวมมากกว่าอยู่สูงกว่า
  2. ผลต่างประตู คือประตูที่ยิงได้ทั้งหมดลบประตูที่เสียทั้งหมด มากกว่าอยู่สูงกว่า
  3. ประตูที่ยิงได้ทั้งหมดมากกว่าอยู่สูงกว่า
  4. ชื่อทีมที่มาก่อนตามลำดับพจนานุกรมอยู่สูงกว่า โดยเทียบแบบเดียวกับ strcmp

ให้พิมพ์สามทีมแรกของตาราง

ข้อมูลเข้า

บรรทัดแรกมีจำนวนเต็ม T และ M โดยที่ 3 ≤ T ≤ 20 และ 0 ≤ M ≤ 500

บรรทัดที่สองมีชื่อทีม T ชื่อ คั่นด้วยช่องว่าง ชื่อเป็นตัวอักษรภาษาอังกฤษยาว 1 ถึง 15 ตัว ไม่ซ้ำกัน

อีก M บรรทัด แต่ละบรรทัดเป็นผลการแข่งขันหนึ่งนัด มีชื่อทีม A ชื่อทีม B จำนวนประตูที่ A ยิงได้ และจำนวนประตูที่ B ยิงได้ คั่นด้วยช่องว่าง A กับ B เป็นคนละทีมกันเสมอ และจำนวนประตูอยู่ระหว่าง 0 ถึง 20

ข้อมูลออก

สามบรรทัด เป็นทีมอันดับที่ 1 ถึง 3 ตามลำดับ แต่ละบรรทัดมีชื่อทีม แต้มรวม ผลต่างประตู และประตูที่ยิงได้ทั้งหมด คั่นด้วยช่องว่าง

4 6
Lions Tigers Eagles Sharks
Lions Tigers 2 1
Eagles Sharks 0 0
Lions Eagles 1 3
Tigers Sharks 4 0
Lions Sharks 2 2
Tigers Eagles 1 1
Eagles 5 2 4
Tigers 4 3 6
Lions 4 -1 5
4 3
Alpha Beta Gamma Delta
Alpha Gamma 10 9
Beta Delta 3 0
Gamma Delta 0 0
Beta 3 3 3
Alpha 3 1 10
Gamma 1 -1 9
ดูคำใบ้

เก็บทีมเป็น struct ที่มีชื่อ แต้ม ประตูได้ และประตูเสีย ทุกนัดหาว่าสองทีมอยู่ช่องไหนด้วย strcmp แล้วบวกค่าให้ทั้งสองทีม จากนั้นเขียนฟังก์ชัน better แบบหน้า 11.4 ที่ไล่ดูทีละเกณฑ์ ต้องการแค่สามอันดับแรก จึงไม่ต้องเรียงทั้งตาราง หาทีมที่ดีที่สุดในบรรดาทีมที่ยังไม่ถูกเลือก ทำสามรอบ และใช้อาเรย์ used จำว่าทีมไหนถูกเลือกไปแล้ว

ดูเฉลย
#include <stdio.h>
#include <string.h>

typedef struct {
    char name[16];
    int points;
    int scored;
    int conceded;
} Team;

Team teams[20];
int used[20];

int find_team(const char name[], int t)
{
    for (int i = 0; i < t; i++) {
        if (strcmp(teams[i].name, name) == 0) {
            return i;
        }
    }
    return -1;
}

void record(Team *team, int scored, int conceded)
{
    team->scored += scored;
    team->conceded += conceded;
    if (scored > conceded) {
        team->points += 3;
    } else if (scored == conceded) {
        team->points += 1;
    }
}

int better(const Team *a, const Team *b)
{
    if (a->points != b->points) {
        return a->points > b->points;
    }
    int diff_a = a->scored - a->conceded;
    int diff_b = b->scored - b->conceded;
    if (diff_a != diff_b) {
        return diff_a > diff_b;
    }
    if (a->scored != b->scored) {
        return a->scored > b->scored;
    }
    return strcmp(a->name, b->name) < 0;
}

int main()
{
    int t, m;
    scanf("%d %d", &t, &m);
    for (int i = 0; i < t; i++) {
        scanf("%s", teams[i].name);
    }
    for (int k = 0; k < m; k++) {
        char home[16], away[16];
        int home_goals, away_goals;
        scanf("%s %s %d %d", home, away, &home_goals, &away_goals);
        record(&teams[find_team(home, t)], home_goals, away_goals);
        record(&teams[find_team(away, t)], away_goals, home_goals);
    }
    for (int rank = 0; rank < 3; rank++) {
        int best = -1;
        for (int i = 0; i < t; i++) {
            if (!used[i] && (best == -1 || better(&teams[i], &teams[best]))) {
                best = i;
            }
        }
        used[best] = 1;
        printf("%s %d %d %d\n", teams[best].name, teams[best].points,
               teams[best].scored - teams[best].conceded, teams[best].scored);
    }
    return 0;
}

ข้อ 8 หุ่นยนต์ส่งของ

ระดับยาก เวลาไม่เกิน 1 วินาที

โกดังขนาดใหญ่ใช้หุ่นยนต์ N ตัวขนของบนพื้นที่แบ่งเป็นช่องตาราง ช่องแต่ละช่องมีพิกัดเป็นจำนวนเต็ม (x, y) หุ่นยนต์แต่ละตัวมีตำแหน่งเริ่มต้น และหันหน้าไปทางทิศใดทิศหนึ่งในสี่ทิศ คือ N เหนือ E ตะวันออก S ใต้ และ W ตะวันตก เดินไปทางเหนือหนึ่งช่อง y เพิ่มหนึ่ง เดินไปทางตะวันออกหนึ่งช่อง x เพิ่มหนึ่ง ทิศใต้และตะวันตกลดลงในทำนองเดียวกัน

ศูนย์ควบคุมส่งคำสั่ง Q คำสั่งตามลำดับ แต่ละคำสั่งสั่งหุ่นยนต์ทีละตัว มีสามแบบ

  • i F K หุ่นยนต์ตัวที่ i เดินตรงไปข้างหน้าตามทิศที่หันอยู่ K ช่อง
  • i L หุ่นยนต์ตัวที่ i หมุนตัวไปทางซ้าย 90 องศา อยู่ที่ช่องเดิม
  • i R หุ่นยนต์ตัวที่ i หมุนตัวไปทางขวา 90 องศา อยู่ที่ช่องเดิม

หุ่นยนต์เดินผ่านกันและอยู่ช่องเดียวกันได้ หลังทำครบทุกคำสั่ง ให้รายงานตำแหน่งและทิศของหุ่นยนต์ทุกตัว และนับว่ามีหุ่นยนต์กี่คู่ที่หยุดอยู่ในช่องเดียวกัน ถ้ามีสามตัวอยู่ช่องเดียวกัน นับเป็น 3 คู่

ข้อมูลเข้า

บรรทัดแรกมีจำนวนเต็ม N และ Q โดยที่ 1 ≤ N ≤ 1000 และ 0 ≤ Q ≤ 100000

อีก N บรรทัด บรรทัดที่ i มีจำนวนเต็ม x y และตัวอักษร d คั่นด้วยช่องว่าง เป็นตำแหน่งและทิศเริ่มต้นของหุ่นยนต์ตัวที่ i โดยที่ -109 ≤ x, y ≤ 109 และ d เป็นหนึ่งใน N E S W

อีก Q บรรทัด แต่ละบรรทัดเป็นคำสั่งหนึ่งคำสั่งตามรูปแบบข้างบน โดยที่ 1 ≤ i ≤ N และ 1 ≤ K ≤ 109

ข้อมูลออก

N บรรทัดแรก บรรทัดที่ i มีพิกัด x y และทิศสุดท้ายของหุ่นยนต์ตัวที่ i คั่นด้วยช่องว่าง บรรทัดสุดท้ายพิมพ์จำนวนคู่ของหุ่นยนต์ที่อยู่ในช่องเดียวกัน

3 7
0 0 N
3 2 W
-1 5 E
1 F 2
1 R
1 F 3
2 L
3 F 4
3 R
3 F 3
3 2 E
3 2 S
3 2 S
3
4 8
0 0 E
5 5 S
2 -3 N
9 9 W
1 F 5
2 F 5
3 F 3
3 R
3 F 3
4 L
4 L
4 L
5 0 E
5 0 S
5 0 E
9 9 N
3
ดูคำใบ้

เก็บทิศเป็นเลข 0 ถึง 3 แทน N E S W ตามลำดับตามเข็มนาฬิกา เลี้ยวขวาคือบวกหนึ่งแล้ว % 4 เลี้ยวซ้ายคือบวกสามแล้ว % 4 และเตรียมอาเรย์ dx กับ dy สี่ช่องไว้บอกว่าแต่ละทิศเดินแล้วพิกัดเปลี่ยนเท่าไร เขียนฟังก์ชันรับ Robot * แล้วแก้ผ่าน -> ตามหน้า 11.4 พิกัดไปได้ไกลถึงประมาณ 1014 ต้องใช้ long long ส่วนการนับคู่ที่อยู่ช่องเดียวกัน เทียบทุกคู่ได้เลย เพราะ N ไม่เกิน 1000

ดูเฉลย
#include <stdio.h>

typedef struct {
    long long x;
    long long y;
} Point;

typedef struct {
    Point pos;
    int dir;
} Robot;

const char DIRECTIONS[] = "NESW";
const int DX[4] = {0, 1, 0, -1};
const int DY[4] = {1, 0, -1, 0};

Robot robots[1000];

int direction_index(char d)
{
    for (int i = 0; i < 4; i++) {
        if (DIRECTIONS[i] == d) {
            return i;
        }
    }
    return -1;
}

void turn_left(Robot *r)
{
    r->dir = (r->dir + 3) % 4;
}

void turn_right(Robot *r)
{
    r->dir = (r->dir + 1) % 4;
}

void forward(Robot *r, long long steps)
{
    r->pos.x += DX[r->dir] * steps;
    r->pos.y += DY[r->dir] * steps;
}

int main()
{
    int n, q;
    scanf("%d %d", &n, &q);
    for (int i = 0; i < n; i++) {
        char d;
        scanf("%lld %lld %c", &robots[i].pos.x, &robots[i].pos.y, &d);
        robots[i].dir = direction_index(d);
    }
    for (int k = 0; k < q; k++) {
        int id;
        char command;
        scanf("%d %c", &id, &command);
        Robot *r = &robots[id - 1];
        if (command == 'F') {
            long long steps;
            scanf("%lld", &steps);
            forward(r, steps);
        } else if (command == 'L') {
            turn_left(r);
        } else {
            turn_right(r);
        }
    }
    int pairs = 0;
    for (int i = 0; i < n; i++) {
        printf("%lld %lld %c\n", robots[i].pos.x, robots[i].pos.y, DIRECTIONS[robots[i].dir]);
        for (int j = i + 1; j < n; j++) {
            if (robots[i].pos.x == robots[j].pos.x && robots[i].pos.y == robots[j].pos.y) {
                pairs++;
            }
        }
    }
    printf("%d\n", pairs);
    return 0;
}