本系列文章将于2021年整理出版,书名《算法竞赛专题解析》。
前驱教材:《算法竞赛入门到进阶》 清华大学出版社
网购:京东 当当      作者签名书

如有建议,请加QQ 群:567554289,或联系作者QQ:15512356

文章目录

  • C.1 计算大数
  • C.2 构造随机数和随机字符串
  • C.3 数组去重
  • C.4 构造测试数据和对拍

  很多人认为Python是最受欢迎的编程语言,它编码简洁,有强大的库。
  Python早已应用在算法竞赛中,能节省大量比赛时间。
  大学的某些算法竞赛(ICPC)已经支持用Python语言提交代码。即使比赛不支持用Python提交代码,而Linux系统一般是预装Python的,可以用Python做辅助工作。
  Python的优点有编码简便、处理大数非常简单、构造测试数据比C++更简单等。Python的主要问题是执行时间慢,比C++、java慢得多,竞赛队员可能不会直接用Python交题。不过,Python可以作为工具使用,常用的是构造数据、写对拍代码。一个典型的应用是:如果能用打表法交题,可以先用python打表出数据,然后用c++或直接用Python提交。
  读者会发现,用Python做这些事,比用C++容易得多,这在紧张的比赛中是很有用的。
  若读者想学习用Python写算法竞赛题的代码,建议到力扣网站(leetcode-cn.com)练习,每个题都有人提交Python题解。
  Python的强大,主要是因为它庞大的库。Python有两种版本Python 2、Python 3,两者不兼容。本节基于 Python 3。Python编译环境下载地址:https://www.python.org/downloads/
  下面介绍Python在算法竞赛中的应用。

C.1 计算大数

  下面的题目是计算大数。


阶乘之和 洛谷 P1009https://www.luogu.com.cn/problem/P1009
题目描述:计算S=1!+2!+3!..+n! (n≤50)


  计算结果是一个天文数字,如果用C++编码,需要用高精度,很复杂。而Java和python都能直接处理大数。
  用Java编码很简单:

import java.math.*;
import java.util.*;
public class Main {public static void main(String[] args) {Scanner in= new Scanner(System.in);int n = in.nextInt();                               BigInteger s = new BigInteger("1");BigInteger ans = new BigInteger("0");for (int i = 1; i <= n; i++) {s = s.multiply(new BigInteger(String.valueOf(i)));ans = ans.add(s);}System.out.println(ans);}
}

  用Python编码更简单:

n = int(input())
s = 1
ans = 0
for i in range(1,n+1,1):    s *= ians += s
print(ans)

C.2 构造随机数和随机字符串

  用Python构造测试数据,比c++简单得多。它能直接产生极大的数字,方便地产生随机字符等。下表列出了一些典型的随机数、随机字符串构造方法1

(1)导入库

import random

  可以写成:

from random import *

  此时后面的代码能够简单一点,例如把random.randint直接写为randint

(2)在指定范围内生成一个很大的随机整数:

print (random.randint(-9999999999999999,9999999999999999))

  输出示例:428893995939258

(3)在指定范围内(0到100000)生成一个随机偶数:

print (random.randrange(0, 100001, 2))

  输出示例:14908
(4)生成一个0到1之间的随机浮点数:

print (random.random())

  输出示例:0.2856636141181378
(5)在指定范围内(1到20)生成一个随机浮点数:

print (random.uniform(1, 20))

  输出示例:9.81984258258233
(6)在指定字符中生成一个随机字符:

print (random.choice('abcdefghijklmnopqrst@#$%^&*()'))

  输出示例:d
(7)在指定字符中生成指定数量的随机字符:

print (random.sample('zyxwvutsrqponmlkjihgfedcba',5))

  输出示例:[‘z’, ‘u’, ‘x’, ‘w’, ‘j’]
(8)导入库

import string

  若写成from string import *,下面的string.ascii_letters改为ascii_letters
(9)用a-z、A-Z、0-9生成指定数量的随机字符串:

ran_str = ''.join(random.sample(string.ascii_letters + string.digits, 8))
print (ran_str)

  输出示例:iCTm6yxN
(10)从多个字符中选取指定数量的字符组成新字符串:

print (''.join(random.sample(['m','l','k','j','i','h','g','d'], 5)))

  输出示例:mjlhd
(11)打乱数组的顺序:

items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
random.shuffle(items)
for i in range(0,len(items),1):      #逐个打印print (items[i]," ",end='')

  输出示例:1 0 8 3 5 7 9 4 6 2

C.3 数组去重

1、整数去重
  随机生成的整数,很多是重复的,而一般情况下需要不重复的数据。下面给出两种去重方法。
  第1种方法用set(),速度极快。set()的时间复杂度差不多是O(n)的,和生成随机数的时间差不多。set()去重不能保持数据的原顺序。set()去重的原理是hash,所以有时候它返回的结果中部分数据看起来像排过序,但整体上并不是有序的。虽然set()去重后的数据的顺序不是那么随机,但是可以用shuffle()再次把数据打乱,得到排序随机的数组。
  第2种方法是暴力去重,非常非常慢,不过它的结果保持了原数据的顺序。

def NonRepeatList1(data):   #函数1:set去重,不保持原顺序return list(set(data))
def NonRepeatList2(data):   #函数2:暴力去重,保持原顺序return [i for n, i in enumerate(data) if i not in data[:n]]
#下面测试上面2个函数
import random
import time
time0 = time.time()
a = []
for i in range(0,100000,1):                #10万个随机数a.append(random.randint(-100000000,100000000))    #随机数取值范围
#print (a)                                 #可以打印数组看看
print ("random time =",time.time()-time0)  #统计随机数的生成时间time0 = time.time()
b = NonRepeatList1(a)                      #去重,不保持原顺序
#print (b)                                 #打印看看顺序
random.shuffle(b)                          #再次打乱顺序
#print (b)                                 #打印看看是否乱序
print ("set time =",time.time()-time0)     #统计set()去重的时间time0 = time.time()
c = NonRepeatList2(a)                      #去重,保持原顺序
#print (c)                                 #打印看看是否保持原序
print ("enum time =",time.time()-time0)    #统计暴力去重的时间

  代码中统计了两种方法的执行时间,在作者的电脑上运行,10万个数的时间是:

random time = 0.10671424865722656
set time = 0.06288003921508789
enum time = 99.96579337120056

  可见set()是极快的,是暴力去重的1600倍。
  再试试1000万个数,生成随机数和去重的时间是:

random time = 10.069396495819092
set time = 10.71152925491333

2、小数去重
  如果要生成不同的小数,简单的办法是先用上面的代码生成去重整数数组,然后把每个整数除以10的幂次即可。例如生成2位小数,把每个整数除以100。

d = []
for i in range(0,len(b),1):         #b是去重后的整数数组d.append(b[i] / 100)

C.4 构造测试数据和对拍

1、构造测试数据
  仍然以Hdu 1425为例。


hdu 1425 sort http://acm.hdu.edu.cn/showproblem.php?pid=1425
给你n个整数,请按从大到小的顺序输出其中前m大的数。
输入:每组测试数据有两行,第一行有两个数n, m(0 < n, m < 1000000),第二行包含n个各不相同,且都处于区间[-500000, 500000]的整数。
输出:对每组测试数据按从大到小的顺序输出前m大的数。


  首先构造测试数据。下面的代码生成60多万个不同的无序的随机数。首先产生100万个随机数,然后用set去重,最后用shuffle打乱即可。

#设本代码的文件名是aa.py
import random
a= []
b= []
for i in range(0,1000000,1):      #100万个随机数a.append(random.randint(-500000,500000))
b=list(set(a))               #去重#print("lena=",len(a))      #验证a的个数是不是100万个
#print("lenb=",len(b))      #b的个数有60多万个random.shuffle(b)          #打乱b
print(len(b),random.randint(1,len(b)))   #打印n、m
for i in range(0,len(b),1):              #逐个打印print ( b[i],end=' ')  #下面的做法是存到一个文件里面,其实不需要
'''
f = open("d:\data.in", "w")    #输出到文件里
print(len(b),random.randint(1,len(b)),file=f)
for i in range(0,len(b),1):      #逐个打印print ( b[i],end=' ',file=f)
f.close()
'''

2、对拍
  下面以Windows环境为例说明构造测试数据和对拍的过程,linux环境类似。
  把上面的代码存为文件aa.py,执行下面的命令,输出测试数据到文件data.in

D:\>C:\Users\hp\AppData\Local\Programs\Python\Python39\python aa.py >data.in

  作者的python安装在目录C:\Users\hp\AppData\Local\Programs\Python\Python39\,读者可以按自己的目录操作,或者设置环境变量,就不用输这个目录了。
  下面给出Hdu 1425的对拍代码,功能是:先输入n和m,然后输入n个数,排序后,打印出前m大的数。与C++对拍代码相比,Python代码更简单。

#设本代码的文件名是bb.py
n,m = map(int,input().split())  #输入n、m
a=[int(n) for n in input().split()]  #输入n个数
a.sort()  #排序
for i in range(n-1,n-m,-1):  #打印出前m-1大的数print ( a[i],end=' ')
print ( a[n-m])              #打印出第m大的数

  把代码存为文件bb.py。Windows环境下,执行以下命令,读输入数据data.in,输出数据到py.out

D:\>C:\Users\hp\AppData\Local\Programs\Python\Python39\python bb.py <data.in >py.out

  前一节“测试数据的构造与对拍https://blog.csdn.net/weixin_43914593/article/details/106863166”的c++代码是:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1000001;
int a[MAXN];
int main(){int n,m;while(~scanf("%d%d", &n, &m)){memset(a, 0, sizeof(a));for(int i=0; i<n; i++){int t;scanf("%d", &t); //此题数据多,如果用很慢的cin输入,肯定TLEa[500000+t]=1;    //数字t,登记在500000+t这个位置}for(int i=MAXN; m>0; i--)if(a[i]){if(m>1)  printf("%d ", i-500000);else      printf("%d\n", i-500000);m--;}}return 0;
}

  设代码的文件名是hash,执行代码,读取输入data.in,输出到文件hash.out

D:\>hash <data.in >hash.out

  下面比较2个代码的输出是否一样,执行以下命令:

D:\>fc py.out hash.out /n

  若文件一样,输出(上面一行中的hash.out,在下面显示HASH.OUT这不是笔误):

正在比较文件 py.out 和 HASH.OUT
FC: 找不到差异

3、把所有过程写成批处理文件2

(1)windows环境
  把上述过程写成windows环境的bat批处理。它是一个死循环,在每个循环生成数据并对拍,直到发现错误,出错误的那组输入和输出都留在文件中,可以查看。下面代码中的路径是作者电脑的路径,请读者改为自己电脑的路径。

@echo off
set path=C:\MinGW\bin
g++ -o hash.exe hash.cpp
:loop
set path=C:\Users\hp\AppData\Local\Programs\Python\Python39
python aa.py >data.in
hash.exe <data.in >hash.out
python bb.py <data.in >py.out
set path=C:\Windows\System32
fc py.out hash.out
if errorlevel == 1 pause
goto loop

(2)linux环境

  linux的文件比较命令是diff。

[root]#diff -c hash.out sort.out

  本文没有在linux环境中试Python,这里给出一个c++的参考,功能类似。

#!bin/bash
while true; dogcc hash.cpp -o hash.exegcc sort.cpp -o sort.exegcc makedata.cpp -o makedata.exe./makedata.exe >data.in./hash.exe <data.in >hash.out./sort.exe <data.in >sort.outif diff hash.out sort.out; thenecho OKelse echo wrongbreakfi
done

  1. 参考https://www.cnblogs.com/zqifa/p/python-random-1.html ↩︎

  2. 感谢华东理工大学17级队员李震 ↩︎

Python在竞赛中的应用-测试数据的构造与对拍 --算法专题精解(31)相关推荐

  1. python处理列表中字典_Python 列表、元组、字典及集合操作详解

    一.列表 列表是Python中最基本的数据结构,是最常用的Python数据类型,列表的数据项不需要具有相同的类型 列表是一种有序的集合,可以随时添加和删除其中的元素 列表的索引从0开始 1.创建列表 ...

  2. Python组合列表中多个整数得到最小整数(一个算法的巧妙实现)

    '''程序功能:    给定一个含有多个整数的列表,将这些整数任意组合和连接,    返回能得到的最小值.    代码思路:    将这些整数变为相同长度(按最大的进行统一),短的右侧使用个位数补齐 ...

  3. python竞赛_浅谈Python在信息学竞赛中的运用及Python的基本用法

    浅谈Python在信息学竞赛中的运用及Python的基本用法 前言 众所周知,Python是一种非常实用的语言.但是由于其运算时的低效和解释型编译,在信息学竞赛中并不用于完成算法程序.但正如LRJ在& ...

  4. 信息学奥赛 python 教程_Python在信息学竞赛中的运用及Python的基本用法(详解)

    前言 众所周知,Python是一种非常实用的语言.但是由于其运算时的低效和解释型编译,在信息学竞赛中并不用于完成算法程序.但正如LRJ在<算法竞赛入门经典-训练指南>中所说的一样,如果会用 ...

  5. 竞赛中常用的Python 标准库

    对竞赛中常用得标准库进行解析和给出代码模板 目录 1.functools 1.1  cmp_to_key 1.2  lru_cache(记忆化存储,加快递归速度) 2.collections 2.1  ...

  6. Python,OpenCV中的K均值聚类——K-Means Cluster

    Python,OpenCV中的K均值聚类 1. 效果图 2. 原理 2.1 什么是K均值聚类? 2.2 K均值聚类过程 2.3 cv2.kmeans(z, 2, None, criteria, 10, ...

  7. Python,OpenCV中的K近邻(knn K-Nearest Neighbor)及改进版的K近邻

    Python,OpenCV中的K近邻(knn K-Nearest Neighbor)及改进版的K近邻 1. 效果图 2. 源码 参考 这篇博客将介绍将K-最近邻 (KNN K-Nearest Neig ...

  8. 竞赛专题(四)特征工程-竞赛中的必杀技

    点击上方"Datawhale",选择"星标"公众号 第一时间获取价值内容 为了帮助更多竞赛选手入门进阶比赛,通过数据竞赛提升理论实践能力和团队协作能力.Data ...

  9. 非科班生如何浑水摸鱼在省级大数据竞赛中获奖

    以各种竞赛为线索的回忆录/经验贴,没写算法啥的,就是记比赛过程,本科除了看的那几本书,打的那十几场竞赛,寝室那几个人,几位恩师的脸,很多都记不清了. 这次记录的比赛是:2017年安徽省大数据技术与应用 ...

最新文章

  1. Python的Crypto模块使用:自动输入Shell中的密码
  2. typora高级设置字体_Mint(Linux)系统设置优化及其常用软件安装笔记
  3. AndroidManifest.xml配置文件属性详解
  4. Cognos TM1_10.1.1服务端配置
  5. php隐藏路径ngnix,thinkphp框架在nginx环境下去掉index.php路径显示
  6. 基于WF4的新平台-流程模式-(9)表单路由启动传入
  7. (67)Verilog HDL模块条件例化
  8. 各种数据库的分页查询
  9. python install_[Python] Linux下python install
  10. html5数学公式编辑器,数学公式编辑器的使用技巧
  11. python逐行写入txt文件_Python中将变量按行写入txt文本中的方法
  12. 《控制论导论》读书:机构-黑箱
  13. openwrt web框架luci简介,20行代码写一个前后端交互页面
  14. 【利用Python进行数据分析】13 - Python建模库介绍
  15. python语言的注释语句引导符不包括什么_以下选项中,哪一个是Python语言中代码注释使用的符号?________...
  16. 优雅的使用MacBook(一些小技巧,你不会知道的)
  17. SEC:马斯克在法官批准和解协议之后再发推特时 并未向公司请示
  18. 1.4 爬虫-笔趣阁获取小说例子
  19. 在10亿像素图像中发现预后模式 FINDING PROGNOSTIC PATTERNS IN GIGAPIXEL IMAGES
  20. Chef学习之三:Chef基础知识 (转贴)

热门文章

  1. python pygame 入门 (一)
  2. 程序员编程表达爱情php,一个程序员的爱情表白书
  3. Libusb-win32编程方法
  4. JAVA数据结构 之 BitSet 类的使用方法
  5. 你想边玩游戏边学编程吗?这篇文章帮你
  6. 通证网【2022】一级注册消防工程报名日期通知
  7. C语言数组的动态分配内存和静态分配内存
  8. 扫码盒获取微信支付宝付款码等信息的前端处理
  9. Python获取文件创建时间
  10. 小学计算机教海探航论文名字,【一附小】寻梦探航话成长 ——一附小“教海探航”论文写作分享会...