【動態規划】01背包問題


  今天小編閑的不行,就打開洛谷,隨便一打卡就是大吉,還宜刷題。

  正巧上午比賽時有一道背包問題,於是小編默默打開試煉場,瞅准了背包問題(別問我為什么),正所謂自知者明,小編也知道自己很水(建議看背包九講),於是挑了三道題:

  在寫之前總得知道什么是背包問題吧,背包問題一般長這樣:

 題目:有N件物品和一個容量為V的背包。第i件物品的費用是w[i],價值是value[i]。求解將哪些物品裝入背包可使價值總和最大。

  那么如何解這種題目呢,先定義一個數組f[i][j]為當一共有i件物品,背包容量為j時的最大價值。然后就要找狀態轉移方程了,小編以前總認為狀態轉移方程難寫,但是只要一項一項列出來就好了。對於每一個物品,無非就兩種可能:要么選,要么不選。那么先看選,凡是總有回報和代價把,選了之后代價是什么呢?想一想,是不是選了之后背包剩余容量就減少了;那么回報呢?當然是價值增加了唄。但是不選就不一樣了,應為啥也沒干,最大價值和之前一樣,不增不減。這不就出來了嘛,兩種情況如下:

  •   選:f[i][j]=f[i-1][j-w[i]]+value[i];
  •        不選:f[i][j]=f[i-1][j];

  因為題目求的是最大價值,所以兩者中取大的就可以了,得到以下狀態轉移方程:

  f[i][j]=max(f[i-1][j-w[i]]+value[i],f[i-1][j]);

  有沒有發現什么,我們用了二維數組,雖然時間上已經難以優化,但是空間上還是可以優化成一維數組的,只要同時去掉i的那一個維度就可以了,因為二維數組有太多不需要一直記錄的,直接不斷更新一維數組(滾動數組的方式)就可以了,更改如下:

  f[j]=max(f[j-w[i]]+value[i],f[j]);

  具體怎么實現,看幾道吧。

  先看第一道:

 

  這道題處於秒殺的行列,直接用剛才的方法,把錢數看成是容量,把重要程度*價格看成是價值就好了,直接寫就行,代碼奉上:

 1 #include<iostream>
 2 using namespace std;
 3 long long cost[30000],w[30000],f[30000],ans;
 4 int main()
 5 {
 6     long long n,m;
 7     cin>>n>>m;
 8     for(int i=1;i<=m;i++)
 9     cin>>cost[i]>>w[i];
10     for(int i=1;i<=m;i++)
11     for(int j=n;j>=cost[i];j--)
12     {
13         if(j>=w[i])
14         f[j]=max(f[j],f[j-cost[i]]+w[i]*cost[i]);
15     }
16     cout<<f[n];
17     return 0;
18 }

先來看一下采葯,比上面的還簡單:

  把時間看成容量,就可以了,代碼獻上:

 1 #include<iostream>
 2 using namespace std;
 3 int t,m,w[1000],cost[1000],f[1000];
 4 int main()
 5 {
 6     cin>>t>>m;
 7     for(int i=1;i<=m;i++)
 8     cin>>w[i]>>cost[i];
 9     for(int i=1;i<=m;i++)
10     for(int j=t;j>=w[i];j--)
11     {
12         f[j]=max(f[j],f[j-w[i]]+cost[i]);
13     }
14     cout<<f[t];
15     
16     return 0;
17 }

最后來看小A點菜:

  這道題乍一看沒思路,還按照剛才的思路:要么吃,要么不吃,吃有什么代價,什么回報呢?錢變少了,方案數變多了唄;不吃呢?還是原來的方案數。這樣兩種情況就出來了:

  •   f[j-cost[i]];
  •        f[j]

   【注意】情況有變,這一次就不那么簡單了,因為選和不選是兩種不同的方案數,題目求的是一共的方案數,所以不是max,不是min,而是+。

  歸根結底長這樣:f[j]=f[j]+f[j-cost[i]];

   這樣代碼就出來了,代碼呈上:

 1 #include<iostream>
 2 using namespace std;
 3 int n,m,cost[100000],f[10000];
 4 int main()
 5 {
 6     cin>>n>>m;
 7     for(int i=1;i<=n;i++)
 8     cin>>cost[i];
 9     f[0]=1;
10     for(int i=1;i<=n;i++)
11     for(int j=m;j>=cost[i];j--)
12     f[j]=f[j]+f[j-cost[i]];
13     cout<<f[m];
14     return 0;
15 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM