一道簡單的演算法題

來源:互聯網
上載者:User
比如
a物品價值1,
b物品價值2,
c物品價值8,
d物品價值10

我給出一個數字 30
求可能的組合

要求為所用到的物品最少,可重複

回複內容:

比如
a物品價值1,
b物品價值2,
c物品價值8,
d物品價值10

我給出一個數字 30
求可能的組合

要求為所用到的物品最少,可重複

@Ukyoi_D 同學的分析很對,只是後面提出的BFS求解剪枝方法並非動態規劃的常見方法,當然,方法也是正確的。

首先規範一下原題:

有n個物品,每個物品的價值為v[i],且 v[0]<=v[i]<=v[i+1]<=v[n-1];給定總價值w,求最小m個物品,使得這m個商品總價值為w.

演算法是動態規劃,證明過程Ukyoi_D 同學已經證明了。這裡給出狀態轉移方程。

狀態轉移方程為:

 f[i][w] = min{   f[i-1][w] if f[i-1][w] exist    ,    f[i-1][w-v[i]] +1 if f[i-1][w-v[i]]exist  }

其中f[i][w]代表在前i個物品中湊足w價值的物品需要的物品數量,f[i][w]存在表示前i個物品可以組合出w價值的物品,不存在表示不能組合出w價值的物品。

對於 f[i][w] 實際上存在3種可能,1. 選i物品,則需要物品數等於f[i-1][w-v[i]]+1。2. 不選i物品,則需要物品等於f[i-1][w], 3. f[i-1][w-v[i]]f[i-1][w]都不存在,則f[i][w]必然也不存在。

三種情況中選出最小的,或者不存在。

具體實現上只需要一個2維數組即可,不存在的狀態用無窮大表示。

這個應該不涉及到演算法啥的,要求所用到的物品最少,那就是盡量使用價值大的物品,
用30從d-》a取整,取餘,整數就是當前的要用多少個,餘數是剩下的,繼續往下運算,直到分配完為止

//===============================
先看一下問題:
1、沒說30一定要分配完
2、要求物品最少

所以我覺得我給出解法沒什麼問題,勉強算貪心演算法

大家都說是背包問題,我認為不是
1、背包問題是兩個維度考慮,重量和價值而這裡只有價值
2、背包問題要求最後價值最大化,這裡僅要求物品最少

問題描述:

有m個物品, 價值從小到大 為V1 - Vm f(i) 為 "價值i且物品最少的組合"的 物品數求解 f(n)

初始化

f(0) = 0f(i) = +∞,1 <= i <= n

求解:

從 1到 nf(i) = min(f(i - Vx) {1 <= x <= m && i >= Vx}) + 1 如果不滿足 1 <= x <= m && i >= Vx, f(i) = +∞

所用到的物品最少,可重複

那就是三個 d,剛好 30。

還有比這個更少的嗎?

另外,這個根本不是背包問題啊,背包問題不僅有價值限制,還有重量限制的啊。

樓上說這個問題“不涉及演算法”顯然是不對的……這是一個多麼經典的動態規劃入門題……
貪心解對30這個特定的值是可行,但比如對16就是不可行的,16的最優解顯然是拿兩個8,而不是貪進法的先拿10再拿三個2。

原題中要用最少的物品湊夠30,假如我先隨便拿一個,比如我拿了一個2,接下來我還要拿28才能滿足“湊夠30”的要求,於是就出現了一個子問題:如何用最少物品湊夠28。同理如果我拿了一個10,子問題就是我需要湊夠20。

這個題目的關鍵在於所謂的“最優子結構”:若且唯若子問題的解是最優的,母問題的解才是最優的。舉例而言,拿第一個東西我可以有1、2、8、10四種選擇,於是這個問題變成四個子問題,假如我已經知道了四個子問題中的某一個的答案是這四個子問題中所拿東西最少的,就比如說需要拿k個吧,那麼加上剛才拿的第一個,那麼原問題就最少需要k+1個。當然實際上我們還不知道這4個子問題究竟哪個的解是最優的,所以就採用遞迴的方法,對四個子問題分別再求子問題,找到所有的二級子問題。在所有二級子問題之中,假如存在一個最優解,比如需要拿m個,那麼同理,一級子問題的解就是至少要拿m+1個,而母問題的解就是要拿m+2個。最優子結構是動態規劃實現的基礎。

具體演算法的實現請看 bluedream 君的解答,那個是動態規劃的標準方法。我下面給出的解答用了遞迴,電腦需要更多資源來處理函數調用,而且通常也更慢。

廣度優先搜尋解法:

剛才的推理建立在“假如知道子問題的解”,當然二級子問題的解實際還是不知道,那就繼續往下找。就這麼像剝洋蔥一樣層層剝開(黑話叫“廣度優先搜尋”)。(這裡有個小trick:先拿8再拿2和先拿2再拿8是一樣的,最佳化掉後可以省一小半資源)

求到若干層之後,比如有一條路線最新的子問題要求拿滿8,此時顯然拿一個8就是這個子問題的最優解。那麼別的路線都可以不用算了,因為別的路線最少也得再拿一個才滿足要求。順著這個找到的最優解一層一層退回去,就找到了整個問題的最優解(之一)。當然也可能某個路線最後發現無解(本題不可能,因為能拿1,總能用1湊夠任何一個正整數,但如果原題目要求拿30塊零5毛那麼顯然無解),那就捨棄這個路線,繼續找其它的路線,直到找到解。或者遍曆所有可能的情況發現無解。

當然上面是“廣度優先”的方法,也可以用“深度優先”的方法,就是說像走迷宮一樣,先順著其中一個子問題(以及這個子問題的子問題)一條道走到黑,如果是死胡同再退回來,換一條路,這個時候找到的第一個解未必是最優解,但是有了這個解的參照,所有比這個解還要深的胡同就可以都標記成死路,不用再鑽了,因為最優解的步驟比剛發現的那個肯定只少不多。如果之後又發現了更優解,就以這個更優的解作新的參照……這樣鑽過所有的路之後,要麼一個最優解也沒發現,要麼最新發現的解就是最優解。

首先,所有手算結果的回答顯然是錯誤的。
題主拿這個只是舉個例子,實際情況當然物品價值和要求解的價值都是程式輸入。
不可能手算出一個結果就說這題沒意義了。

其次,上面@ekea0407 所說的貪心解法是錯誤的。
假設物品重量按題目說是1,2,8,10,要求解的重量是16,這個時候按貪心演算法:
16=10+6=10+2+4=10+2+2+2,變成4件物品。
其實16=8+8,只需要2件物品。

最後,這個問題和背包問題還是有點區別吧,只是都用動態規劃求解,求解過程也類似。
@brayden 的解法就行。
用暴力搜尋遍曆解空間的解法是很差的,因為暴力搜尋沒有把已經找到過的局部解儲存下來,會多次求解同一問題。
這個題還是用動態規劃合適。

感覺樓主這個問題幾乎不涉及演算法. 先用3個10,直接30了.如果有不用10的話,直接就比3個多了,問題就沒有進行下去的必要了.

背包問題
動態規劃

這是背包問題,上面一位同學說這個不涉及到演算法,其實是不科學的。題主可以網上搜尋一下樓教主的‘背包九講’,這個問題就迎刃而解了。

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.