Music Problem 01揹包優化

2021-10-05 12:09:36 字數 1430 閱讀 5226

一道很不錯的題目,綜合了多個知識點。

題意:給你n個數,判斷能否在這n個數中選一些數組成3600的倍數。

先給這個題的一般形式。

給你n個數,判斷能否在這n個數中選一些數組成m的倍數。

(1 ≤ n ≤ 1e6, 2 ≤ m ≤ 1e3)

然後我們可以發現乙個01揹包的解法(時間複雜度:o(n*m))

狀態:dp[i][j]表示從1到i個數中能否選一些數組成m(0表示不可以,1表示可以)。

狀態轉移方程: dp[i + 1][(j + a[i]) % m] = 1 if dp[i][j] = 1

這裡可以考慮用滾動陣列優化一下。

但是這個時間複雜度肯定過不去,然後我們考慮優化。

有三種優化策略:二進位制優化,bitset 或者 抽屜原理。

這裡主要講抽屜原理優化,其餘的優化也會給出**。

當n>=m的時候,肯定可以從這n個數中選擇一些數組成m的倍數,直接輸出yes即可。

為什麼呢?利用乙個取餘的性質( (a + b) % mod = (a%mod +b%mod) % mod )以及抽屜原理.

定義sum陣列為這n個數的字首和陣列,即sum[i]=a[1]+a[2]+.....a[i-1]+a[i]

分為兩種情況考慮:

情況一:存在乙個k(1 <= k <= n),使得sum[k] % m == 0,那麼就得證;

情況二:對於任意的k(1 <= k <= n),都有sum[k] % m != 0,那麼餘數的種類只有 1 到 m-1 總共 m-1 種情況,但是有 m 個 sum,由抽屜原理可知必然有兩個sum(假設為sum[i],sum[j],j > i)的餘數相同。因此 (sum[j] - sum[i]) % m = (sum[j] % m - sum[i] % m) = 0;

**實現:

#include#includeusing namespace std;

int a[150000];

int dp[3605],f[3605];

int main()

if(dp[0]) printf("yes\n");

else printf("no\n");}}

}

二進位制優化的**(來自已退役的cds學長):

#include#include#includeusing namespace std;

int v, s[3600], dp[18005];

void alone(int use)

}void every(int use)

}void mulit(int n, int use)

if (dp[0]) puts("yes");

else puts("no");

}return 0;

}

揹包 01揹包

01揹包 有n種物品與承重為m的揹包。每種物品只有一件,每個物品都有對應的重量weight i 與價值value i 求解如何裝包使得價值最大。dp i,v 表示前i個物體 包括第i個 面對容量為v的揹包的最大價值,c i 代表物體i的重量,w i 代表物體i的價值 如果第i個物體不放入揹包,則揹包...

又見01揹包(01揹包題目3)

時間限制 1000 ms 記憶體限制 65535 kb 難度 3 描述 有n個重量和價值分別為wi 和 vi 的 物品,從這些物品中選擇總重量不超過 w 的物品,求所有挑選方案中物品價值總和的最大值。1 n 100 1 wi 10 7 1 vi 100 1 w 10 9 輸入多組測試資料。每組測試資...

揹包專題 01揹包

暑假集訓開始了,按照隊裡的分配,我是弄dp的,嘛,於是我又一次的開始了從01揹包開始學習,昨天將杭電的幾道01揹包重新做了一遍,下面講講我自己對於01揹包的理解。首先01揹包題目的雛形是 有n件物品和乙個容量為v的揹包。第i件物品的費用是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。...