Skip to content

Bài 39: Tổ Chức Code & Chuẩn Bị Nộp Bài

Tác giả: FPTOJ Team
Nội dung: Kỹ năng tổ chức code, quản lý thư mục, chuẩn bị nộp USB

1. Tại sao phải tổ chức code?

Bạn code xong 3 bài, đến lúc nộp USB → tìm file không ra, copy nhầm file cũ, quên xóa debug → mất điểm oan!

Tổ chức code tốt = nộp bài an toàn = không mất điểm vô ích.


2. Cấu trúc thư mục thi đấu

2.1. Trên máy thi (trước khi copy lên USB)

D:\THI_HSG\
├── template.cpp          ← Template chung (copy sẵn)
├── bai1\
│   ├── bai1.cpp          ← Code bài 1
│   ├── test\             ← Thư mục test
│   │   ├── 1.in          ← Input test 1
│   │   ├── 1.out         ← Expected output 1
│   │   ├── 2.in
│   │   ├── 2.out
│   │   └── ...
│   └── run.bat           ← Script chạy test
├── bai2\
│   ├── bai2.cpp
│   ├── test\
│   └── run.bat
├── bai3\
│   ├── bai3.cpp
│   ├── test\
│   └── run.bat
└── submit\               ← Thư mục chuẩn bị nộp
    ├── bai1.cpp
    ├── bai2.cpp
    └── bai3.cpp

2.2. Trên USB (nộp bài)

1
2
3
4
USB:\
├── bai1.cpp
├── bai2.cpp
└── bai3.cpp

Lưu ý: Chỉ nộp file .cpp đã xóa debug, đã test kỹ!


3. Script tạo thư mục thi đấu (Windows)

Lưu thành setup_thi.bat, chạy 1 lần trước khi thi:

@echo off
echo Tao cau truc thu muc thi dau...

mkdir D:\THI_HSG
mkdir D:\THI_HSG\bai1\test
mkdir D:\THI_HSG\bai2\test
mkdir D:\THI_HSG\bai3\test
mkdir D:\THI_HSG\bai4\test
mkdir D:\THI_HSG\bai5\test
mkdir D:\THI_HSG\submit

echo Da tao xong!
echo.
echo Cau truc:
echo D:\THI_HSG\
echo ├── bai1\ (code + test)
echo ├── bai2\ (code + test)
echo ├── bai3\ (code + test)
echo ├── submit\ (file chuan bi nop)
echo └── template.cpp

pause

4. Script compile & chạy test (Windows)

Lưu thành run.bat trong mỗi thư mục bài:

@echo off
setlocal enabledelayedexpansion
REM ===== Compile =====
g++ -std=c++17 -O2 -Wall -o bai1.exe bai1.cpp
if errorlevel 1 (
    echo COMPILE ERROR!
    pause
    exit /b 1
)

REM ===== Chạy test =====
echo Dang chay test...
set pass=0
set fail=0

for %%f in (test\*.in) do (
    set "filename=%%~nf"
    bai1.exe < "%%f" > "test\temp.out"
    fc /W "test\%%~nf.out" "test\temp.out" > nul
    if errorlevel 1 (
        echo [FAIL] Test %%~nf
        set /a fail+=1
    ) else (
        echo [PASS] Test %%~nf
        set /a pass+=1
    )
)

echo.
echo Ket qua: !pass! PASS, !fail! FAIL
pause

5. Script chuẩn bị nộp bài

Lưu thành prepare_submit.bat trong D:\THI_HSG\:

@echo off
echo ===== CHUAN BI NOP BAI =====
echo.

REM Xóa thư mục submit cũ
if exist submit\*.cpp del /q submit\*.cpp

REM Copy code vào thư mục submit
echo Copy bai1...
copy bai1\bai1.cpp submit\ > nul

echo Copy bai2...
copy bai2\bai2.cpp submit\ > nul

echo Copy bai3...
copy bai3\bai3.cpp submit\ > nul

echo Copy bai4...
copy bai4\bai4.cpp submit\ 2>nul

echo Copy bai5...
copy bai5\bai5.cpp submit\ 2>nul

echo.
echo ===== DA COPY XONG =====
echo.
echo Kiem tra thu muc submit:
dir /b submit\

echo.
echo ===== KIEM TRA DEBUG =====
echo Dang kiem tra debug macro trong code...

findstr /C:"debug(" submit\*.cpp >nul 2>&1
if not errorlevel 1 (
    echo [CANH BAO] Tim thay debug macro! Xoa truoc khi nop!
) else (
    echo [OK] Khong tim thay debug macro
)

findstr /C:"cerr" submit\*.cpp >nul 2>&1
if not errorlevel 1 (
    echo [CANH BAO] Tim thay cerr! Xoa truoc khi nop!
) else (
    echo [OK] Khong tim thay cerr
)

echo.
echo ===== KIEM TRA COMPILE =====
for %%f in (submit\*.cpp) do (
    g++ -std=c++17 -O2 -Wall -o test_compile.exe "%%f" 2>nul
    if errorlevel 1 (
        echo [LOI] %%f khong compile duoc!
    ) else (
        echo [OK] %%f compile duoc
        del test_compile.exe 2>nul
    )
)

echo.
echo ===== CHUAN BI NOP USB =====
echo Copy thu muc submit vao USB...
echo.
echo Nhan phim bat ky de tiep tuc...
pause >nul

REM Copy vào USB (thay E: bằng ký tự USB của bạn)
REM xcopy submit\*.cpp E:\ /Y

echo.
echo DA XONG! Kiem tra USB truoc khi nop!
pause

6. Script sinh testcase tự động

Lưu thành gen_test.cpp:

#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int randInt(int l, int r) {
    return uniform_int_distribution<int>(l, r)(rng);
}

// ===== Sinh testcase cho bài tìm đường =====
void genPathTest(int testId) {
    int n = randInt(2, 20);
    int m = randInt(n-1, min(n*(n-1)/2, 50));

    ofstream inp("test/" + to_string(testId) + ".in");
    inp << n << " " << m << endl;

    // Sinh cây trước (đảm bảo liên thông)
    for(int i = 2; i <= n; i++) {
        int par = randInt(1, i-1);
        int w = randInt(1, 100);
        inp << par << " " << i << " " << w << endl;
    }

    // Sinh thêm cạnh
    for(int i = n; i <= m; i++) {
        int u = randInt(1, n);
        int v = randInt(1, n);
        while(v == u) v = randInt(1, n);
        int w = randInt(1, 100);
        inp << u << " " << v << " " << w << endl;
    }
    inp.close();
}

// ===== Sinh testcase cho bài mảng =====
void genArrayTest(int testId) {
    int n = randInt(1, 20);
    int valMin = randInt(-100, 0);
    int valMax = randInt(0, 100);

    ofstream inp("test/" + to_string(testId) + ".in");
    inp << n << endl;
    for(int i = 0; i < n; i++) {
        inp << randInt(valMin, valMax);
        if(i < n-1) inp << " ";
    }
    inp << endl;
    inp.close();
}

int main() {
    // Sinh 10 test
    for(int i = 1; i <= 10; i++) {
        genArrayTest(i);
        // genPathTest(i);  // Bỏ comment nếu là bài đồ thị
    }
    cout << "Da sinh 10 test!" << endl;
    return 0;
}

7. Script stress test

Lưu thành stress_test.cpp:

#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int randInt(int l, int r) {
    return uniform_int_distribution<int>(l, r)(rng);
}

// ===== Brute force (chắc chắn đúng) =====
int bruteForce(vector<int>& a) {
    int maxSum = INT_MIN;
    for(int i = 0; i < a.size(); i++) {
        int sum = 0;
        for(int j = i; j < a.size(); j++) {
            sum += a[j];
            maxSum = max(maxSum, sum);
        }
    }
    return maxSum;
}

// ===== Code cần test =====
int mySolution(vector<int>& a) {
    int maxSum = a[0], curSum = a[0];
    for(int i = 1; i < a.size(); i++) {
        curSum = max(a[i], curSum + a[i]);
        maxSum = max(maxSum, curSum);
    }
    return maxSum;
}

int main() {
    int testCount = 0;
    int failCount = 0;

    while(failCount == 0) {
        testCount++;

        // Sinh testcase
        int n = randInt(1, 20);
        vector<int> a(n);
        for(auto& x : a) x = randInt(-100, 100);

        // Chạy cả 2
        int expected = bruteForce(a);
        int actual = mySolution(a);

        if(expected != actual) {
            failCount++;
            cout << "BUG FOUND at test " << testCount << "!" << endl;
            cout << "Input: n=" << n << endl;
            for(auto x : a) cout << x << " ";
            cout << endl;
            cout << "Expected: " << expected << endl;
            cout << "Actual: " << actual << endl;
        }

        if(testCount % 10000 == 0) {
            cout << "Da test " << testCount << " test, chua tim thay bug..." << endl;
        }
    }

    cout << endl;
    cout << "Tong cong: " << testCount << " test, " << failCount << " bug" << endl;
    return 0;
}

8. Workflow hoàn chỉnh khi thi

Bước 1: Chuẩn bị (trước khi thi)

1
2
3
4
5
1. Format USB
2. Chạy setup_thi.bat → tạo thư mục
3. Copy template vào mỗi thư mục bài
4. Kiểm tra g++ hoạt động
5. Chuẩn bị giấy + bút

Bước 2: Khi nhận đề (10 phút đầu)

1
2
3
4
5
6
1. Đọc TẤT CẢ đề
2. Ghi ra giấy:
   Bài 1: [mô tả ngắn] — ★ Dễ
   Bài 2: [mô tả ngắn] — ★★ Trung bình
   Bài 3: [mô tả ngắn] — ★★★ Khó
3. Quyết định thứ tự làm bài

Bước 3: Làm bài (120-250 phút)

1
2
3
4
5
6
7
1. Mở thư mục bài1/
2. Copy template vào bai1.cpp
3. Code bài 1
4. Tạo test/sample trong test/
5. Chạy run.bat → kiểm tra
6. Nếu xong → chuyển bài 2
7. Lặp lại cho bài 2, 3...

Bước 4: Kiểm tra (20 phút cuối)

1
2
3
4
1. Chạy run.bat cho TẤT CẢ bài
2. Kiểm tra edge cases thủ công
3. Xóa debug macro
4. Kiểm tra output format

Bước 5: Nộp bài (5 phút cuối)

1
2
3
4
5
1. Chạy prepare_submit.bat
2. Kiểm tra thư mục submit/
3. Copy submit\ vào USB
4. Kiểm tra USB đọc được
5. Nộp USB

9. Lưu ý quan trọng

9.1. LUÔN có backup

1
2
3
- Copy code ra nhiều nơi (USB, ổ cứng, Desktop)
- Lưu version cũ trước khi sửa (bai1_v1.cpp, bai1_v2.cpp)
- USB dự phòng (nếu được phép)

9.2. KHÔNG code trực tiếp trên USB

1
2
3
Sai lầm: Code trực tiếp trên USB → mất dữ liệu nếu USB hỏng

Đúng: Code trên ổ cứng → copy vào USB khi nộp

9.3. Kiểm tra compile TRƯỚC khi nộp

1
2
3
4
# Compile thử TẤT CẢ bài
g++ -std=c++17 -O2 -Wall -o test bai1.cpp
g++ -std=c++17 -O2 -Wall -o test bai2.cpp
g++ -std=c++17 -O2 -Wall -o test bai3.cpp

9.4. Kiểm tra output format

1
2
3
- Thừa/thiếu khoảng trắng → WA
- Thừa/thiếu xuống dòng → WA
- In hoa/thường khác đề → WA

10. Bài tập luyện tập

Tạo thư mục thi đấu mẫu và thử workflow:

Bài Mục đích
Tạo thư mục D:\THI_HSG\ Luyện setup
Viết template.cpp Luyện template
Tạo run.bat Luyện test tự động
Tạo 5 test cho 1 bài Luyện sinh test
Chạy stress test Luyện tìm bug

Bài tập thực hành workflow

Sau khi đã setup xong, thử nộp bài trên các nền tảng để quen workflow:

Bài Nền tảng Độ khó Mục đích
CSES - Weird Algorithm CSES Quen nộp bài online
CSES - Missing Number CSES Luyện đọc input/output
CSES - Repetitions CSES Luyện template + test
CSES - Increasing Array CSES Luyện stress test
CSES - Permutations CSES Luyện edge cases

Tài liệu tham khảo

Bài trước: Debug & Mẹo ← | Bài tiếp theo: Về trang tổng hợp →


💬 Bình luận