- 題目來源:2020華爲軟件精英挑戰賽–初賽
- 題目說明:
2.1 輸入信息:輸入爲包含資金流水的文本文件,每一行代表一次資金交易記錄,包含本端賬號ID, 對端賬號ID, 轉賬金額,用逗號隔開。
本端賬號ID和對端賬號ID爲一個32位的無符號整數
轉賬金額爲一個32位的無符號整數
轉賬記錄最多爲28萬條
每個賬號平均轉賬記錄數< 10
賬號A給賬號B最多轉賬一次
舉例如下,其中第一行[1,2,100]表示ID爲1的賬戶給ID爲2的賬戶轉賬100元:
1,2,100
1,3,100
2,4,90
3,4,50
4,1,95
2,5,95
5,4,90
4,6,30
6,7,29
7,4,28
2.2 輸出信息:輸出信息爲一個文件,包含如下信息:
第一行輸出:滿足限制條件下的循環轉賬個數。
說明:數據集經過處理,會保證滿足條件的循環轉賬個數小於300萬。
第二行開始:輸出所有滿足限制條件的循環轉賬路徑詳情。
輸出循環轉賬路徑要按照指定排序策略進行排序:每條循環轉賬中,ID(ID轉爲無符號整數後)最小的第一個輸出;總體按照循環轉賬路徑長度升序排序;同一級別的路徑長度下循環轉賬賬號ID序列,按照字典序(ID轉爲無符號整數後)升序排序。
舉例如下:
4
1,2,4
1,3,4
4,6,7
1,2,5,4
2.3 限制條件:循環轉賬的路徑長度最小爲3(包含3)最大爲7(包含7),例如賬戶A給賬戶B轉賬,賬戶B給賬戶A轉賬,循環轉賬的路徑長度爲2,不滿足循環轉賬條件。 - 題目理解:
說明:2,4,1,2 是長度爲 3 的環,按照升序的要求是:1,2,4
本案例是以鄰接表的形式找環,利用 sort 對 graph.keys() 得到的 key 值進行從小到大的排序,爲了在找環過程中出現重複找環的情況,進行了剪枝優化,即:比自己小的 key 不再去查找,本案例用的最基本的 for 循環,對於十萬以內的環查找速度較快,但是不建議用python 程序參加比賽,主要是太慢了。當然自己也想過用多進程多線程進行優化,然而效果並沒有多大的提升,本文可以很好的幫助小白理解操作,大佬不喜勿噴啊,畢竟作爲一個妹子碼代碼不容易,自己一個人走了太多的彎路了,不過個人很歡迎大佬前來指導一二。
廢話不多說,下面上代碼。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/4/23 13:04
# @Author : xueli
# @Software: win10 Tensorflow1.13.1 python3.6.3
import time
def func(graph,s):#graph圖 s指的是開始結點
path =[]
for x1 in graph[s]:
if x1 > s:
try:
nodes2 = graph[x1]
except KeyError as e:
pass
else:
for x2 in nodes2:
if x2 > s:
try:
nodes3 = graph[x2]
except KeyError as e:
pass
else:
for x3 in nodes3:
if s == x3:
A = [s,x1,x2]
if len(set(A)) == len(A):
path.append(A)
elif x3 > s:
try:
nodes4 = graph[x3]
except KeyError as e:
pass
else:
for x4 in nodes4:
if s == x4:
A = [s,x1,x2,x3]
if len(set(A)) == len(A):
path.append(A)
elif x4 > s:
try:
nodes5 = graph[x4]
except KeyError as e:
pass
else:
for x5 in nodes5:
if s == x5:
A = [s,x1,x2,x3,x4]
if len(set(A)) == len(A):
path.append(A)
elif x5 > s:
try:
nodes6 = graph[x5]
except KeyError as e:
pass
else:
for x6 in nodes6:
if s == x6:
A = [s,x1,x2,x3,x4,x5]
if len(set(A)) == len(A):
path.append(A)
elif x6 > s:
try:
nodes7 = graph[x6]
except KeyError as e:
pass
else:
for x7 in nodes7:
if s == x7:
A = [s,x1,x2,x3,x4,x5,x6]
if len(set(A)) == len(A):
path.append(A)
else:
break
return path
def savePredict(AA2):
t2 = time.time()
with open(result_name, 'w') as f:
f.write(str(len(dd))+'\n')
for aa in AA2:
ww = str(aa)
q1 = ww.strip(']')
qq = q1.strip('[')
bb = qq.replace(" ", "")
f.write(str(bb)+"\n")
print('write_time', time.time() - t2)
if __name__ == '__main__':
t1 = time.time()
file_name = "./data/test_data.txt"
result_name = "result.txt"
with open(file_name) as f:
a = []
c = []
for line in f.readlines():
line = line.strip('\n') # 去掉換行符\n
b = line.split(',') # 將每一行以空格爲分隔符轉換成列表
a.append(int(b[0]))
c.append(int(b[1]))
print('read_time', time.time() - t1)
graph = {}
data_list = [a,c]
for x in range(len(a)):
if a[x] in graph:
graph[a[x]] += [c[x]]
else:
graph[a[x]] = [c[x]]
s = sorted(graph.keys())
t4 = time.time()
dd = []
for i in s:
d = func(graph, i)
if d != []:
for ii in d:
dd.append(ii)
dd.sort()
print('func_time', time.time() - t4)
AA2 = sorted(dd, key=lambda i: len(i), reverse=False)
print(len(dd))
savePredict(AA2)
print('總時:', time.time() - t1)
運行結果:
代碼和數據已經上傳到GitHub,感興趣的可以下載下來。
https://github.com/xueli-lxl/python