您的位置 首页 kreess

審計中的算法1——查找對方科目中的遞歸、回溯與剪枝算法(零基礎入門Python算法)

本系列其他文章:審計中的算法2——自動填寫EXCEL底稿中的進制轉換(Python算法入門教程)審計中的算法與人工智能3——銀行/客商全稱與簡稱模糊匹配中的 動態規劃、編輯

本系列其他文章:審計中的算法2——自動填寫EXCEL底稿中的進制轉換(Python算法入門教程)審計中的算法與人工智能3——銀行/客商全稱與簡稱模糊匹配中的 動態規劃、編輯距離算法 與 自然語言處理應用

1.引言

做過審計工作的讀者都知道,對方科目是賬目分析要用到的重要數據,比如勾稽分析時需要精確的對方科目和金額分析賬款的去向

而客戶在給我們序時賬時,其中的數據往往是不帶對方科目的,需要我們自行計算

之前用AudTool(使用VSTO開發)的對方科目精確查找模式,讓我還算性能不錯的電腦在項目辦公室裡卡死瞭足足15分鐘,當時我就非常疑惑——一張憑證一般隻有幾條數據,算個對方科目至於這麼卡嗎?

在結束瞭那年年報審計的工作後,為瞭不再在關鍵時刻掉鏈子,我決定自己開發一個更快的版本(令人震驚的是,我沒有找到有人開發過更好的版本,甚至很多審計師都不知道對方科目可以自動生成),其中遇到的算法問題感覺很適合作為算法入門科普,於是就有瞭這篇文章

本文2~5節引入瞭一些算法在審計、會計上的應用案例和經典問題,為沒有接觸過算法的讀者做鋪墊,從 6.為什麼算法必須優化? 開始講述核心問題,本文代碼使用Python3語言,並對代碼做瞭詳細的註釋,編程小白也能快速理解

需要註意的是,本人並非專業的計算機相關工作者,還請各位讀者幫忙糾正文中的一些錯誤


2.本問題的會計知識背景

如果你是沒有做過審計或者會計工作的讀者,可以先聽我說說後面那些問題的應用場景,避免不知道算法有什麼意義

在會計記賬時,記一次帳需要記錄兩個方向(借和貸),兩個方向的金額是相等的

比如我們使用銀行存款購買1000元的原材料,會減少1000元的銀行存款,增加1000元的原材料,記賬會記成這樣

可以發現,借方加起來和貸方加起來是相等的,且借方和貸方是對應的,這種“對應”就是對方科目,這裡的對方科目就很明顯瞭

(對會計感興趣的詳見:會計中關於借貸怎麼區分,感覺好亂啊,求指導?? – 夜鶯的回答)

看到這,你會覺得查找對方科目是很簡單的事情,找另一邊金額一樣的不就完事瞭?可在很多情況下它們會出現一對多、多對多、甚至不在另一邊而是負數在同一邊的情況,如:

空行隔開表示不同的會計憑證

可以發現想找到對方科目並不是一件簡單的事,接下來我們進入正題——怎麼通過數學辦法編寫腳本找到對方科目


3.這個問題為什麼深奧——由兩數之和問題說起

我們從一對多開始講起,把一對多這個問題簡化下,比如固定成一對二

這樣問題就可以簡化成:

稍作思考就可以發現一個最簡單的辦法——窮舉所有兩兩相加的情況,得到相加等於100 和 30 的兩個數

def twoSum(nums,target): #定義一個名為twoSum的函數,它需要提供nums(一組數字)和target(要求的相加結果)兩個信息來計算結果
n = len(nums) #得到你提供名為nums的一組數字中有多少個數字,結果保存到名為n的變量,如果nums是[60,40,20,10],那n=4
for i in range(n): #從0開始循環到n,循環到0到n的哪裡保存到名為i的變量,因為python列表是從0開始的,這樣方便從列表中取值
for j in range(i + 1, n): #在循環中循環,從 i+1 開始循環到n,這樣做是為瞭跳過自己和已經求過的數,不理解可以看後面圖例,循環到第幾個保存到名為j的變量
print(nums[i],"+",nums[j],"=",nums[i] + nums[j]) #為便於理解,打印窮舉的結果

twoSum([60,40,20,10],100) #調用函數,傳入需要的兩個參數

'''
運行結果如下
60 + 40 = 100 60 + 20 = 80 60 + 10 = 70 40 + 20 = 60 40 + 10 = 50 20 + 10 = 30
'''

#加一個判斷和返回,讓得到結果後結束計算並返回要的結果即可

def twoSum2(nums,target): #定義一個名為twoSum的函數,它需要提供nums(一組數字)和target(要求的相加結果)兩個信息來計算結果
n = len(nums) #得到你提供名為nums的一組數字中有多少個數字,結果保存到名為n的變量,如果nums是[60,40,20,10],那n=4
for i in range(n): #從0開始循環到n,循環到0到n的哪裡保存到名為i的變量,因為python列表是從0開始的,這樣方便從列表中取值
for j in range(i + 1, n): #在循環中循環,從 i+1 開始循環到n,這樣做是為瞭跳過自己和已經求過的數,不理解可以看後面圖例,循環到第幾個保存到名為j的變量
if nums[i] + nums[j] == target: #判斷nums的第i項與nums的第j項相加是否等與target
return [nums[i],nums[j]] #如果是,返回這兩個數

twoSum2([60,40,20,10],100) #調用函數,傳入需要的兩個參數

'''
返回結果如下
[60,40]
'''

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

返回顶部