刚参加完人生中第一个程序设计比赛,虽然没有进入复赛,但是还是感觉有所收获的。在这里把成果分享一下,也算给自己一个圆满的收尾。
初赛训练地图的调度时间是2000以内;比赛地图代码提交慢了,不过调度时间也比较长,将近10000,没有充足的时间来调试,所以输得心服口服。不过怎么我们队也是江大独苗嘛,也进过前20⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄,争了口气!
代码贴在Git 2019HuaWei--JZE
这是一个车辆调度问题,文件资料我也贴在Git上了,大家可以自行钻研,这里就不解读了。
首先实现将道路(Road)通过路口(Cross)信息连接起来,获得地图完整的道路状况,如某条道路起点在那个路口,终点在哪个路口,前后各能通向哪里等。
这里实现的逻辑如果从程序看上去,是比较复杂的,首先我们给出Road、Cross和Car的三个类定义:
class CROSS(object):
def __init__(self,ID,road1,road2,road3,road4):
self.ID = ID
self.road1 = road1
self.road2 = road2
self.road3 = road3
self.road4 = road4
class ROAD(object):
left_road = None
right_road = None
stright_road = None
back_left = None
back_right = None
back_stright = None
all_right = 1
def __init__(self,ID,length,speed_lim,channels,cross_begin,cross_end,isDuplex):
self.ID = ID
self.length = length
self.speed_lim = speed_lim
self.channels = channels
self.cross_begin = cross_begin
self.cross_end = cross_end
self.isDuplex = isDuplex
class CAR(object):
now_post = None
def __init__(self,ID,start_loc,dest_loc,speed,start_time):
self.ID = ID
self.start_loc = start_loc
self.dest_loc = dest_loc
self.speed = speed
self.start_time = start_time
然后读取训练地图的信息:
cars = pd.read_csv(r"C:\Users\Administrator\Desktop\JZE\1-map-training-1\car.txt",skipinitialspace = True)
roads = pd.read_csv(r"C:\Users\Administrator\Desktop\JZE\1-map-training-1\road.txt",skipinitialspace = True)
crosses = pd.read_csv(r"C:\Users\Administrator\Desktop\JZE\1-map-training-1\cross.txt",skipinitialspace = True)
然后创建三类对象链表,其中,在初始化Cross对象时进行Road道路信息写入
car_dict = {}
for car_info in cars.iterrows():
car_dict[car_info[1][0].replace("(","")] = CAR(car_info[1][0].replace("(",""),car_info[1][1],car_info[1][2],car_info[1][3],car_info[1][4].replace(")",""))
road_dict = {}
for road_info in roads.iterrows():
road_dict[road_info[1][0].replace("(","")] = ROAD(road_info[1][0].replace("(",""),road_info[1][1],road_info[1][2],road_info[1][3],road_info[1][4],road_info[1][5],road_info[1][6].replace(")",""))
cross_dict = {}
for cross_info in crosses.iterrows():
the_cross = cross_info[1][0].replace("(","")
fir = str(int(cross_info[1][1]))
sec = str(int(cross_info[1][2]))
thi = str(int(cross_info[1][3]))
fot = str(int(cross_info[1][4].replace(")","")))
if fir != "-1":
if cross_info[1][0].replace("(","") == str(road_dict[fir].cross_begin):
if (road_dict[fir].isDuplex == "1"):
road_dict[fir].back_left = road_dict[sec] if sec != "-1" and ((road_dict[sec].isDuplex == "1") or str(road_dict[sec].cross_begin) == the_cross) else None
road_dict[fir].back_stright = road_dict[thi] if thi != "-1" and ((road_dict[thi].isDuplex == "1") or str(road_dict[thi].cross_begin) == the_cross) else None
road_dict[fir].back_right = road_dict[fot] if fot != "-1" and ((road_dict[fot].isDuplex == "1") or str(road_dict[fot].cross_begin) == the_cross) else None
else:
road_dict[fir].back_left = None
road_dict[fir].back_stright = None
road_dict[fir].back_right = None
else:
road_dict[fir].left_road = road_dict[sec] if sec != "-1" and ((road_dict[sec].isDuplex == "1") or str(road_dict[sec].cross_begin) == the_cross) else None
road_dict[fir].stright_road = road_dict[thi] if thi != "-1" and ((road_dict[thi].isDuplex == "1") or str(road_dict[thi].cross_begin) == the_cross) else None
road_dict[fir].right_road = road_dict[fot] if fot != "-1" and ((road_dict[fot].isDuplex == "1") or str(road_dict[fot].cross_begin) == the_cross) else None
...
...
...
cross_dict[cross_info[1][0].replace("(","")] = CROSS(cross_info[1][0].replace("(",""),road_dict[fir] if fir in road_dict else None,road_dict[sec] if sec in road_dict else None,\
road_dict[thi] if thi in road_dict else None,road_dict[fot] if fot in road_dict else None)
for index,item in road_dict.items(): #以列表返回可遍历的(键, 值) 元组数组
print("当前道路:",item.ID,"\t直行:",item.stright_road.ID if item.stright_road != None else None,"\t左转:",item.left_road.ID if item.left_road != None else None,"\t右转:",item.right_road.ID if item.right_road != None else None,\
"\t反直:",item.back_stright.ID if item.back_stright != None else None,"\t反左:",item.back_left.ID if item.back_left != None else None,"\t反右:",item.back_right.ID if item.back_right != None else None)
这里为了方便理解,上面程序只贴出对于路口一的判断来说明:
首先判断cross中的road1的起点是否为该cross。如果是,那么判断road1是否为双向:如果为双向,那么将该路口其他三条road分别作为road1的反向道路写入;如果是单向线,那么road1只能从起点通往终点,那么该路口的其他road就不能通过road1到达,即road1的反向三个路口为None。如果road1起点不是该cross(则该cross是road1终点),那么该cross的其他三条road边肯定是road1的前向三路口,且能到达。(大家好好琢磨一下赛制和规则,这里就好理解了)
实现道路后,下面就是按照一个规则(算法)来实现道路分配,这里提一下,听说大佬们都用的退火做的,保持各赛区最低系统调度时间。我们这里就简单了一下,所以时间比较高。。。也不能说懒,就没花时间去钻研吧,所以唉。。。追悔莫及有点过,多多少少还是有遗憾的。
这里我是按照当前car所在cross和car终点两个位置来作比较得到car的行驶路线的,这样容易出现找不到终点一直徘徊的情况(因为不是越靠近终点的road就一定有条路通向终点,之后正式比赛更是如此)。所以如果出现这样的情况,我就让徘徊不前的路暂时关闭,然后倒退重新搜索;如果本轮搜索不到终点,即road全部被关闭,那么重新选择初始道路重新进行一轮道路规划(car的起点是cross,一个cross有多个road,所以car的起点也有多个)。
至于小车的出发时间,哈哈哈~我们就更偷懒了,抱着侥幸的心理我们是给了一个“像样”的随机策略来给小车安排出发时间的。
所以这两部分的代码,我就不贴出来献丑了,需要的画直接去2019HuaWei--JZEclone吧(如果觉得还行的话,可否给个给个星星呢(*>.<))
说明一下,Git上的代码是根据比赛要求的SDK进行编写的,如果你要本地跑的话,把读取文件的地方改一下就好。
上面的是初赛训练地图的程序,比赛地图的规模大了很多,而且cross信息也不像训练地图那么简单,所以程序也做了很大的修改,主要有如下两点:
决赛程序的调整和运行效率调整主要是我们队长负责的,我理解的差不多就这样啦,欢迎各位大佬交流讨论!
本篇属于原创,所以就不贴搬运工啦。