競賽總分

題目描述

學生在咱們USACO的競賽中的得分越多咱們越高興。
咱們試着設計咱們的競賽以便人們能儘量的多得分,這須要你的幫助。
咱們能夠從幾個種類中選取競賽的題目,這裏的一個"種類"是指一個競賽題目的集合,解決集合中的題目須要相同多的時間而且能獲得相同的分數。你的任務是寫一個程序來告訴USACO的職員,應該從每個種類中選取多少題目,使得解決題目的總耗時在競賽規定的時間裏而且總分最大。輸入包括競賽的時間,M(1 <= M <= 10,000)(不要擔憂,你要到了訓練營中才會有長時間的比賽)和N,"種類"的數目1 <= N <= 10,000。後面的每一行將包括兩個整數來描述一個"種類":
第一個整數說明解決這種題目能得的分數(1 <= points <= 10000),第二整數說明解決這種題目所需的時間(1 <= minutes <= 10000)。
你的程序應該肯定咱們應該從每一個"種類"中選多少道題目使得能在競賽的時間中獲得最大的分數。
來自任意的"種類"的題目數目多是任何非負數(0或更多)。
計算可能獲得的最大分數。算法

·(看到這裏感受是個揹包,qwq)

輸入

第 1 行: M, N--競賽的時間和題目"種類"的數目。
第 2-N+1 行: 兩個整數:每一個"種類"題目的分數和耗時。數組

輸出

單獨的一行包括那個在給定的限制裏可能獲得的最大的分數。架構

樣例輸入

300 4
100 60
250 120
120 100
35 20

樣例輸出

605

思路

這道題目麼,是讓咱們求的是最大的分數,看到這個數據範圍也只有二維DP。
\[ O(N^2)過萬吧,沒問題的。 \]學習

  • [x] 其實我還見過

\[ O(N^2)過百萬的呢。 \]
讓咱們來分析這個二維DP:spa

題目說的競賽時間其實轉換成揹包問題就是揹包的容量,N表示有N件物品設計

每件物品有質量和體積。他說要最多,不可能只選一組的,因此這也能選一些。其實這些物品的總價值就是所給數據的答案。code

因此正解是徹底揹包啊。(徹底揹包是什麼請參考百度百科)遞歸

具體一點的呢?內存

等一下別急。模板

來說一下徹底揹包。

首先先將二維的打法:

設fij仍是表示前i件物品放入一個爲j容量的揹包得到的最大價值,爲第i件物品的是否選擇的方案.

而後能夠得出狀態轉移方程式:

當這件物品選的時候

f[i][j] = f[i][j-a[i]]+w[i];

選的時候就把a[i]這個耗時給減掉再加上得分。

當這件物品不選的時候

f[i][j] = f[i-1][j];

不選的時候就保留上一個的最優解.

因而這個代碼架構就出來了。

for(int i = 1; i <= n ; i++){
        for(int j = 1; j <= m ;j++){
            if(j < a[i]) f[i][j] = f[i-1][j];
            else if(f[i-1][j] > f[i][j-a[i]]+w[i]) f[i][j] = f[i-1][j];
            else f[i][j] = f[i][j-a[i]]+w[i];
        }
    }

循環 i -> n:

​ 循環 j -> m

當j < a[i] 的時候,已經確保了最優解因而不選。

當上一個的最優解已經大於當前解的話,那麼也是能夠不選的。

其餘狀況都要選。

答案放在 fnm ,輸出就能夠了。

放一個簡介的狀態轉移方程:

f[i][j]=max{f[i-1][j-k*c[i]]+k*w[i]|0<=k*c[i]<=j}

而後再講一維的打法:

有些時候出題人很討厭,故意讓你炸內存,讓二維揹包不過。

這個時候要用一維的打法的(前題是二維數組大於5000 * 5000 的時候, 二維 RE)。

其實不用i這一維度,只用j,空間複雜度大大降低了。

循環要改一下。

1 -> n 不變

​ w[i] -> m 避免重複

一維的思路:

這件物品選:

if(f[j-w[i]]+a[i] > f[j]){
    f[j] = f[j-w[i]]+a[i];
 }

當前的大於以前的則更新。

不然不幹。

不選的狀況:沒有處理。

一維的代碼架構就出來了:

for(int i = 1; i <= n ; i++){
        for(int j = w[i]; j <= m ;j++){
            if(f[j-w[i]]+a[i] > f[j]){
                f[j] = f[j-w[i]]+a[i];
            }
        }
    }

綜合一下上面的狀態轉移方程

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

答案存在f[m]輸出就能夠了。

  • (確實一維要好打的多,其實同樣啊)

總結

針對不一樣的題目使用不一樣的代碼。

這道題爲了內存,我仍是寫了一維過了。

二維jj 91 分 ,見祖宗啊。

歸根到底這只是一道徹底揹包的模板題,最後以排名第一的成績A了。

  • (我太弱了,還要。。。qwq)

學習徹底揹包要懂得:

  • [x] 什麼是動態規劃。

  • [x] 什麼是遞推算法。
  • [x] 什麼是記憶化搜索。
  • [x] 什麼是遞歸算法。

才能更好的理解。

End.

相關文章
相關標籤/搜索