使用 Python 參與算法競賽


引言

眾所周知,打算法競賽最頻繁使用的語言是 C++。然而,對於那些不卡復雜度的題目,可以考慮使用 Python 編寫(因為 Python 真的好寫)。

本文將簡單地介紹一些 Python 使用技巧和語法糖。

一些技巧

框架

初學 Python 時,由於 Python 著名的交互性,大家可能會直接逐行編寫 Python 語句。然而,這樣便於代碼邏輯組織和函數的編寫。如同 C++ 中的 int main() { ... } 一樣,Python 中也可以構建類似的程序框架。

def foo():
    print("Hello")

def main():
    foo()

if __name__ == '__main__':
    main()

最后一句的意義為:

  • 當執行本文件時,正常運行 main() 函數;
  • 當從外部調用文件時,可以導入本文件中編寫的函數,而不執行 main() 函數。

這樣,保證了編寫的代碼既可以執行,又可以外部調用。

全局變量

Python 中的全局變量需要在函數中用 global 命令聲明后才能進行修改,例子如下。

x = 0

def foo():
    x += 10

def bar():
    global x
    x += 10

def main():
    foo()
    bar()

調用 foo() 會拋出 UnboundLocalError: local variable 'x' referenced before assignment

具體原因參看 Python中的global關鍵字,你了解嗎

重定向輸入輸出

如同 C++ 中的 freopen() 函數,Python 中也有將標准 I/O 重定向到文件的命令。

import sys
sys.stdin = open(r'hack.txt', 'r')
sys.stdout = open(r'hack.out', 'w')

這樣就可以把樣例放到 hack.txt 中,輸出到 hack.out 中了。

_debug_

Python 中有一個內置常量 __debug__,其默認值為 True。當編譯命令中開啟 -O 時,其值為 False

我用這個技巧來替代 C++ 中的 #if(n)def ... #else ... #endif 語句(不同於 C/C++,Python 沒有預編譯過程,故也沒有完全對應的命令)。

默認 OJ 是不會開啟 -O 命令的(不過還是在提交前查看 OJ 對應的語言編譯命令說明為好),所以我們可以定義一個常量

LOCAL = not __debug__ # True if compile option '-O'

這樣我們在本地運行開啟 -O 命令之后,就可以使用

if LOCAL:
    print("Hello")

來指定本地編寫時執行但 OJ 不執行的命令。

例如將上一節的重定向可以加上這句,就不用擔心由於忘記注釋掉重定向而收獲一發 RE 了

斷言

Python 的斷言關鍵字與 C++ 相同,都是 assert;在拋出 AssertionError 時可以指定報錯信息。例子如下:

a, b = 1, 2
assert a == b, f'{a} != {b}'

終端會拋出 AssertionError: 1 != 2

隨機數生成器與對拍

隨機數生成

例如生成 A+B problem 的隨機數據。生成的數據直接輸出到 hack.txt 中。

import sys
from random import *

# seed(12345)
sys.stdout = open(r'hack.txt', 'w')

n = int(1e3)
print(n)
for i in range(n):
    a = randint(-1e9, 1e9)
    b = randint(-1e9, 1e9)
    print(a, b)

對拍

檢驗兩個程序是否有相同輸出,構造樣例和 debug 時常用。

不一定是兩個 *.exe,只要是有輸入輸出的東西都可以拍。

from os import system

while True:
    system("python3 randgen.py")
    system("true.exe < ../hack.txt > true.txt")
    system("false.exe < ../hack.txt > false.txt")
    if system("fc true.txt false.txt"):
        system("pause")

更進階的用法,考慮使用 洛谷推出的對拍工具 CYaRon,使用 pip 直接安裝即可。

代碼運行計時

使用標准庫中的 time 模塊

import time

if __name__ == '__main__':
    T1 = time.time()
    main()
    T2 = time.time()
    print("Runtime: %.3f s." % (T2 - T1), file=sys.stderr)

print() 的 kwg 中指定 file=sys.stderr 使得運行時間在終端輸出。這樣當重定向輸入輸出時,該語句不受影響。

不過通常來講,選擇使用 Python 編寫時,基本都是對運行時間要求不高的題目。

模板

貼上自用的 Python 模板

#!/usr/bin/python3
import sys
import os
import time
from functools import reduce
from math import *

LOCAL = not __debug__  # True if compile option '-O'


def main():
    pass


if __name__ == "__main__":
    T1 = time.time()
    if LOCAL:
        sys.stdin = open(r"hack.txt", "r")
        sys.stdout = open(r"hack.out", "w")
    t = int(input())  # 1
    for i in range(t):
        print(f"Case #{i+1}:", end=' ')
        main()
    T2 = time.time()
    print("Runtime: %.3f s." % (T2 - T1), file=sys.stderr)

我的賽前模板倉庫

git clone git@github.com:RivTian/Python-Content.git

參考

  1. Python 3 官方文檔 - 中文 https://docs.python.org/zh-cn/3/
  2. Python 中的 global 關鍵字,你了解嗎?https://zhuanlan.zhihu.com/p/111284408


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM