套裁問題之踩坑記

2021-08-16 20:29:10 字數 2772 閱讀 9182

前些天乙個老哥要我做個板材套裁的東東,我看了下覺得很簡單,結果一腳就踩了個大坑。

套裁就是在板材加工之前如何裁板,就是從指定規格的原材中如何最小消耗的裁出需要數量的各種板材。我一想,這不就是個揹包問題嗎,結果做起來才發現想得太簡單了,在第一步就暈了:如何找出所有可用的揹包(即如何放置待切割板材)。

套裁問題和揹包問題最大的區別就是面積之和上能放下的未必就能符合放入的矩形不能重合的約束,所以套裁需要對放置進來的矩形進行定位。也就是說,將要切割的矩形放到原材中時,是需要確定放到**才可以的。而通常的揹包問題則只要簡單的算下數量之和就可以了,也就是說,套裁其實是在通常的揹包問題上還要滿足特定放置點的約束。

這些特定放置點其實就是原材和已經放入的矩形的四個頂點,每個頂點可以有四個方位、橫豎兩個方向進行嘗試放置,演算法思路很簡單,用迭代就ok了,但問題在於,每放乙個矩形就可能多了三個頂點,而當待放入的目標矩形和大板大小差得比較多時,這就演變成了乙個比指數增長還可怕的計算問題。

我一開始理解錯了乙個板的切割問題時,加入了乙個遠小於原材的小矩形時,等了二十分鐘,發現怎麼還在算?!我有些奇怪,就打了個debug,看到的情況是:

我們簡單估算下:27個頂點,每個頂點有8個放置方案,每個放置方案要測試24個矩形,即一趟需探測:27*8*24=5184(當然有很多重複,但這不重要),是不是很小意思啦,然後,請24次方!!也就是2的快300次方了,而現在的cpu才只有64位啊!

我這才意識到自己把問題想簡單了,雖然這種估算是用最後一次迭代的資料來估之前的情況,會大大的放大計算量,但計算量到了這個地步,這種估算的誤差已經可以不必太計較了。

因為已經答應了老哥,總不能食言啊,只好暫時放過這個問題,在用盡了洪荒之力終於暫時控制住了這個問題的複雜度之後,才發現這個小板竟然是開在另乙個板子上的,我根本不需要管的,當時真是有一口血噴在螢幕上的感覺啊:(

這個第一步其實就相當於揹包問題中找出各種揹包的過程,所以在暫時控制住了包包的複雜度之後,問題就回到了揹包問題的正軌。這就簡單了,我之前介紹過用蟻群演算法來解決這類問題,所以蹭蹭蹭就寫好了演算法,可執行結果依然讓我**:我頭一次見到在這樣複雜的問題上,計算機竟然輸給了人!!

老哥給了我乙個類似軟體的計算結果,是96張原材,可他們自己手算的結果是94張原材,還只需要3種切割圖案就可以了,可我算了一兩天最好的結果都要用到104張原材!想了半天不得要領,甚至把老哥他們的手算結果自己都算了好幾次,最後還是得回來檢查自己的演算法。

開始的時候,我是按將石頭往揹包裡放(即將每個需要切割的板材向原材中放)的思路,這種方法看來有些不對頭,所以乾脆調整成拿著揹包找石頭(即在每張原材中放板材,放不下了則換張新的原材),一通昏天暗地的調整之後,嗯,結果很明顯啊,我也終於算出96張了!!

真是被打敗了,在計算機這麼擅長的的問題上計算機竟然會輸給了人?!

然後就是開始調整演算法的各種引數,可調了一天,就只能算到96張,這怎麼可能呢?!對於這樣存在著相當大數量最優解的問題,蟻群演算法是一定可以找出來的啊?!我思來想去,最後只好跟蹤演算法是如何一步步新增矩形的,才終於發現了問題。在之前討論蟻群演算法的文章裡,我說過螞蟻在挑選自己的下一步時要依靠兩種資訊:

這裡的問題就在於這個啟發性知識。一般來說,蟻群演算法作為一種高效的元演算法,其對啟發性知識並不是很依賴,一般只需要提供乙個優化方向就可以了,畢竟蟻群演算法是依靠成群的螞蟻組團血拼,即是以規模用量(盡可能多的探索)來降低對質(領域知識上的深刻)上的要求,這也是其可以作為一種應用廣泛的元演算法的原因所在。但在套裁問題上,顯然出了點問題。

本來,我認為這個啟發性知識就是盡量提高原材的利用率就可以了,但看過各個矩形的新增順序後發現,由於小矩形的組合比較有利於提高利用率,所以這種啟發性知識的設定導致了小矩形會被優先挑選走,而在大量的小矩形被挑走後,再增加大矩形,就沒有合適的小矩形可以和大矩形進行配對了。

找到原因就好辦了,我調整了啟發性知識的計算方法,即在每個原材增加第乙個矩形時優先挑選大矩形。當我滿懷信心的再次執行演算法後,咦?!怎麼竟然會沒有效果呢?!再仔細一研究,原來,先挑大矩形會導致第二大的矩形一直得不到挑選,直到最大的矩形挑完後,終於可以開始挑次大矩形的時候,小矩形也都被挑的七七八八了。意識到這個問題後,自然就明白了這個啟發性知識就是在挑第乙個矩形時既要盡量先挑大的,還要盡量先挑剩餘數量多的。

然後再試,哦,95張了,我是該笑呢,還是該哭呢:(

不過,有了每張原材是如何挑第乙個矩形的經驗,我自然也就看到了解決問題的曙光:問題肯定出在了後繼矩形該怎麼挑上了。

後繼矩形的挑選其實就是盡量先挑可以提高原材利用率的,還要盡量先挑剩餘數量多的。

按這個思路重新調整了啟發性知識後,ok,終於,終於,終於,我也算出了94張啦:)

反思下本次踩坑的經驗教訓:

總的來說,套裁問題其實是乙個多約束問題,而多約束問題的解決顯然需要對各約束的平衡進行小心的權衡與調整,這就需要反覆的運算以尋找到合適的平衡點。

最後,對比人配置的結果,程式還有乙個很明顯的缺陷,即人可以只用3種切割圖案就完成這個最優的套裁方案,而我即便是放出了500只螞蟻,反覆計算了500次,最好的也不過是17種切割圖案。難道,人還真能在這個問題上打敗計算機嗎?!

我仔細研究了老哥所給的板材規格的資料,發現這是一組經過精心設計的特定規格,也就是說這些板材規格和原材規格之間有著非常明顯的匹配關係,人進行配置其實就是按照這種匹配關係直接套就可以了。這就使得人所配置出來的方案,其實存在著一種更強的約束。而當一次需要套裁出的成品數量上公升時,可以產生最優套裁方案的切割圖案會指數性上公升,想在成千上萬種可行的切割圖案中找到這麼獨特的切割圖案是極小概率的運氣,除非加入這種特定約束,否則是根本不可能的。

而如果打破這種匹配關係,顯然人就不行了。當我逐步縮小原材規格,使得人的這種特定匹配關係不再成立時,得到了乙個有趣的結果:

也就是說,人的這種配置方案,其實是用原材的冗餘或說浪費為代價來實現的,而這種代價的成本顯然是非常高昂的,導致成本起碼提高了5%啊:(

mybatis LocalCache踩坑記錄

上週週三下午,準備去吃飯的時候,值班突然找過來說使用者操作時爆出訂單不存在的問題,因為之前做了分表連續很長一段時間都沒問題,而且當時找過來的都是一些因為產品或者qa操作不當找不到記錄的情況,就沒有在意這些,當時以為幾分鐘就能搞定,但是沒想到居然是線上日誌爆出的問題,經過驗證訂單確實不存在!心想完了,...

AdMob接入踩坑記

首先列出參考文件 admob官方參考鏈結 我是cocos2d x v3.9的工程,在按照官方文件接入之後,出現一堆編譯錯誤例如 plain view plain copy undefined symbols for architecture arm64 objc class glkview refe...

python codecs 模組踩坑記

之前在使用 codecs 模組進行檔案讀寫的時候,常用習慣 如下 import codecs 讀取data codecs.open file name r utf 8 read 寫入fw codecs.open file name w utf 8 fw.write data 之前這麼寫好像也沒什麼問...