[VBA] 規劃求解的實際運用 (AI解)

更新於 2024/04/30閱讀時間約 7 分鐘

問題:

前幾天,LINE Meiko微課頻道 社群,奇大哥 不吝分享某個 Facebook 社團內問題的神奇解法。雖然我對數字沒啥概念,只好請出【神隊友 AI】來幫忙~



前言:

在數據導向的商業環境中,規劃求解技術是解決複雜問題的關鍵工具之一。這類技術尤其在財務和營運策略中顯得重要,其中需確定一組變量的最佳組合以達成特定目標。Excel VBA(Visual Basic for Applications)提供了一個強大的平台,使非程式設計背景的專業人士也能夠實現複雜的數據處理和自動化任務。

本文將通過一個實際例子—找出一組數值之和最接近指定目標—來探討規劃求解在實際應用中的流程和技術。



問題說明:

在這個案例中,所面對的挑戰是從 Excel 表格的 A 欄(A1 到 A16)中挑選幾個數字,使得所選數字的總和最接近 D1 單元格中的目標值(30303)。這是一個典型的優化問題,常見於財務領域,比如說配置資產組合以達到最接近預期回報的目標。

從 A1 ~ A16 挑選幾個數字,放入 E欄 內並加總後,才會使得 F1 和 D1 的值相等或最接近 ?

從 A1 ~ A16 挑選幾個數字,放入 E欄 內並加總後,才會使得 F1 和 D1 的值相等或最接近 ?



程式設計:

步驟一:讀取數據

首先,程式需要從 Excel 工作表中讀取數據。這包括從 A2 到 A16 的數據(由於 A1 是標題),以及 D1 單元格中的目標值。

步驟二:設計算法

為了解決這個問題,使用了一種稱為「回溯算法」(Backtracking),這是一種系統地遍歷所有可能組合的方法,以找到最佳解。這個算法從第一個數字開始,逐個檢查加入或不加入該數字的結果,並根據當前的組合計算總和,進而評估其接近目標值的程度。

步驟三:處理數據類型

在 VBA 中,數字處理的默認類型是 Integer,但當處理的數值或計算的範圍超過 Integer 所能表示的範圍時,就會導致溢位錯誤。為了避免這一問題,將所有的數字變數改用 Long 類型,它提供了更大的數值範圍。

步驟四:實現並優化

實現算法後,程式會逐一試驗所有可能的數字組合,計算每一組合的總和並與目標值比較,記錄下最接近的組合和相應的差異。為了提高效率,限制了組合的數量,避免不必要的計算。

步驟五:輸出結果

當找到最佳組合後,程式會將這些數值從 A 欄複製到 E 欄,讓結果數值能夠直觀地顯示出來。



程式碼實現:

下面是實現上述功能的 VBA 程式碼示例:

Sub FindClosestSum()

Dim target As Long
Dim nums As Range, cell As Range
Dim bestSum As Long, bestDiff As Long
Dim currSum As Long, currDiff As Long
Dim i As Long, combinations As Long
Dim bestCombination As String, currCombination As String
Dim eColumnIndex As Long

' 設定目標值和數字範圍
target = Sheets("Sheet1").Cells(1, 4).Value ' D1 單元格的值
Set nums = Sheets("Sheet1").Range("A2:A16") ' A欄的範圍

' 初始化最佳差異為一個很大的數
bestDiff = 99999999

' 初始化 E 欄索引
eColumnIndex = 1


' 計算所有可能的組合
combinations = 2 ^ nums.Cells.Count - 1
If combinations >= 2147483647 Then combinations = 2147483647 ' 限制組合數量以避免溢位


For i = 1 To combinations
currSum = 0
currCombination = ""
For Each cell In nums
If (i And 2 ^ (cell.Row - nums.Row)) <> 0 Then
currSum = currSum + cell.Value
currCombination = currCombination & cell.Row & ", "
End If
Next cell


' 計算當前組合的差異
currDiff = Abs(currSum - target)


' 更新最佳解
If currDiff < bestDiff Then
bestDiff = currDiff
bestSum = currSum
bestCombination = Left(currCombination, Len(currCombination) - 2)
End If
Next i


' 將最佳組合的數值寫入 E 欄
If bestCombination <> "" Then
Dim rowIndexes As Variant
rowIndexes = Split(bestCombination, ", ")
For i = LBound(rowIndexes) To UBound(rowIndexes)
Sheets("Sheet1").Cells(eColumnIndex + 1, 5).Value = Sheets("Sheet1").Cells(rowIndexes(i), 1).Value
eColumnIndex = eColumnIndex + 1
Next i
End If


' 輸出結果
MsgBox "Best sum: " & bestSum & vbNewLine & _
"Closest difference: " & bestDiff & vbNewLine & _
"Combination of rows: " & bestCombination

End Sub



檔案下載



結論:

這個案例不僅展示了如何使用 VBA 解決具體的規劃求解問題,還反映了計算技術如何幫助我們達成所要的目標。通過這樣的實踐,專業人士可以更好地理解並利用數據,進而在複雜的商業環境中做出更精確的決策。 VBA 的這種應用不僅限於財務規劃,其在各種業務過程中的潛力是巨大的,值得每一位專業人士深入學習和掌握。



參考文獻




以上就是這次的分享,請持續關注  和 Meiko微課頻道,謝謝大家 ~

有任何問題,請到【opa的沙龍】【Excel VBA 情境學習】一起討論有關 VBA 的問題,或加入 LINE社群 Meiko微課小綠群(粉絲交流群)


歡迎您的加入。

內容總結
規劃求解
5
/5
avatar-img
128會員
44內容數
Meiko微課頻道主要以辦公室應用為出發點,針對上班族群所遇到的問題進行分享
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
本文介紹如何使用 ChatGPT 4 計算兩個民國日期之間的差異。同時提到了使用函數 DATEDIF 和神奇的【R鍵】來解決問題。
5/5ChatGPT4的函數設計
本文介紹如何使用 萬金油 做出輔助列,以達成下拉選單的要求。將詳細討論如何處理資料範圍變動、萬金油公式和快速新增名稱的技巧。此外,也分享了三個參考影片以供學習。
5/5萬金油公式
INDIRECT 函數一般都使用【A1樣式】來做參照,本文將揭開 INDIRECT 函數,鮮為人知的【R1C1樣式】運用方法。
5/5INDIRECT【R1C1樣式】
這篇文章介紹了一個在 Excel 中將郵遞區號加上括號的公式,並分析了公式的原理。這是一篇對於 Excel 公式拆解感興趣的人有價值的文章。
過去,在Excel中使用核取方塊時,我們常受限於其大小,一直無法輕易調整。最近的E365版本解決了這個問題,但舊版本的Excel卻沒有這個新功能。因此,在這裡,Meiko將跟同學們分享如何在新舊版本中輕鬆放大核取方塊,而且不受數量的限制。 實際操作請參考影片教學,影片中提供的語法請參考本篇文章
本篇主要是設計,當【沒有任何數值】與【原本就有數值】這兩種情況結合在一起時的 VBA 解決方案。分享內容包括張忍大師的函數解決方法。文章中包含影片檔案下載以及參考文獻連結。
本文介紹如何使用 ChatGPT 4 計算兩個民國日期之間的差異。同時提到了使用函數 DATEDIF 和神奇的【R鍵】來解決問題。
5/5ChatGPT4的函數設計
本文介紹如何使用 萬金油 做出輔助列,以達成下拉選單的要求。將詳細討論如何處理資料範圍變動、萬金油公式和快速新增名稱的技巧。此外,也分享了三個參考影片以供學習。
5/5萬金油公式
INDIRECT 函數一般都使用【A1樣式】來做參照,本文將揭開 INDIRECT 函數,鮮為人知的【R1C1樣式】運用方法。
5/5INDIRECT【R1C1樣式】
這篇文章介紹了一個在 Excel 中將郵遞區號加上括號的公式,並分析了公式的原理。這是一篇對於 Excel 公式拆解感興趣的人有價值的文章。
過去,在Excel中使用核取方塊時,我們常受限於其大小,一直無法輕易調整。最近的E365版本解決了這個問題,但舊版本的Excel卻沒有這個新功能。因此,在這裡,Meiko將跟同學們分享如何在新舊版本中輕鬆放大核取方塊,而且不受數量的限制。 實際操作請參考影片教學,影片中提供的語法請參考本篇文章
本篇主要是設計,當【沒有任何數值】與【原本就有數值】這兩種情況結合在一起時的 VBA 解決方案。分享內容包括張忍大師的函數解決方法。文章中包含影片檔案下載以及參考文獻連結。
你可能也想看
Google News 追蹤
Thumbnail
徵的就是你 🫵 超ㄅㄧㄤˋ 獎品搭配超瞎趴的四大主題,等你踹共啦!還有機會獲得經典的「偉士牌樂高」喔!馬上來參加本次的活動吧!
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
瞭解Powerpoint程式的主要架構是由物件和屬性組成,指定物件變得非常重要。在準備投影片時,命名變得非常重要,以避免控制出現問題。文章介紹如何透過VBA來控制Powerpoint中的投影片。
Thumbnail
1.宣言指定代稱活頁簿或頁籤 2.同時控制兩個活頁簿 3.調整欄寬、刪除欄
Thumbnail
1. 如何開始巨集(VBA) 2. 初步認識編寫VBA的面板 3. 儲存啟用VBA的活頁簿檔案
Thumbnail
影片展示 營收月年增率用來做什麼? 【一起學程式】這次要帶大家來一起看一下如何用EXCEL VBA抓取營收報價,抓取營收報價來看營收年增率與股價之間的表現情況。 月營收年增率= 月營收YoY =( 當年某月營收-去年某月營收)÷ 去年某月營收x 100% 在這篇你會學到的技巧有: 程式設計的構想
Thumbnail
Excel VBA 簡單的網頁爬蟲
Thumbnail
https://www.youtube.com/watch?v=AUq-BqPG500 程式執行只有配樂展示,無講話 前言: 這次跟大家分享一下怎麼用EXCEL VBA抓取Goodinfo中,經營績效理不同分頁的資料,如上圖。 文後會附上程式範例給大家做參考。 4.資料整理,欄位定位。
Thumbnail
這篇是記錄一下透過VBA抓取goofinfo股息跟報價的方式。適合對VBA做投資工具設計有興趣的朋友閱讀,因為這個比較進階,有興趣再研究。
Thumbnail
開啟F12開發人工具 取得CSV下載網址 利用巨集協助編寫簡易程式
Thumbnail
我們將介紹如何根據自己的需要自定義操作流程,提高Word使用的效率和便捷性。在本文中,我們將介紹如何利用VBA在Word中自動插入底稿頁尾。
Thumbnail
徵的就是你 🫵 超ㄅㄧㄤˋ 獎品搭配超瞎趴的四大主題,等你踹共啦!還有機會獲得經典的「偉士牌樂高」喔!馬上來參加本次的活動吧!
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
瞭解Powerpoint程式的主要架構是由物件和屬性組成,指定物件變得非常重要。在準備投影片時,命名變得非常重要,以避免控制出現問題。文章介紹如何透過VBA來控制Powerpoint中的投影片。
Thumbnail
1.宣言指定代稱活頁簿或頁籤 2.同時控制兩個活頁簿 3.調整欄寬、刪除欄
Thumbnail
1. 如何開始巨集(VBA) 2. 初步認識編寫VBA的面板 3. 儲存啟用VBA的活頁簿檔案
Thumbnail
影片展示 營收月年增率用來做什麼? 【一起學程式】這次要帶大家來一起看一下如何用EXCEL VBA抓取營收報價,抓取營收報價來看營收年增率與股價之間的表現情況。 月營收年增率= 月營收YoY =( 當年某月營收-去年某月營收)÷ 去年某月營收x 100% 在這篇你會學到的技巧有: 程式設計的構想
Thumbnail
Excel VBA 簡單的網頁爬蟲
Thumbnail
https://www.youtube.com/watch?v=AUq-BqPG500 程式執行只有配樂展示,無講話 前言: 這次跟大家分享一下怎麼用EXCEL VBA抓取Goodinfo中,經營績效理不同分頁的資料,如上圖。 文後會附上程式範例給大家做參考。 4.資料整理,欄位定位。
Thumbnail
這篇是記錄一下透過VBA抓取goofinfo股息跟報價的方式。適合對VBA做投資工具設計有興趣的朋友閱讀,因為這個比較進階,有興趣再研究。
Thumbnail
開啟F12開發人工具 取得CSV下載網址 利用巨集協助編寫簡易程式
Thumbnail
我們將介紹如何根據自己的需要自定義操作流程,提高Word使用的效率和便捷性。在本文中,我們將介紹如何利用VBA在Word中自動插入底稿頁尾。