HDU 2844Coins 涉及包含三種揹包問題

2021-08-09 03:33:28 字數 2121 閱讀 1291

給你n種面值分別為a1,a2,a3………..an的硬幣,每種硬幣對應的數量分別是c1,c2,c3………cn。問:在可以湊出多少種不同的面值,湊出來的面值必須在1~m之間。

乍一看以為是母函式問題,但的確可以使用母函式(在不顧時間的情況下也可以得出正確答案),由於題目所給的數值太大,m <= 100000,而硬幣數量ci <= 1000。這套用母函式簡直就被炸飛了。最終還得老老實實用動態規劃。

乍二看,這不是多重揹包問題嗎,直接三個for迴圈幹上去,很悲劇,肯定超時,資料這麼大,兩個for迴圈都有可能崩,更別說三個了。

最終還是弱弱的參考了大神們的**,發現這道題雖然套著多重揹包的羊皮,但其實卻需用到01揹包與完全揹包的概念才能在不超時的情況下跑過。

這裡安利乙個講述完全揹包的部落格:

感覺講的超級棒!!!

第二個技巧:當ai * ci >= m時,就沒必要再使用二進位制優化了,此時可以直接把這種面值的硬幣當成無限多個,直接上完全揹包的模板。如果優化成二進位制比不優化還慢。

第三個技巧:採用滾動陣列,由於n*m的最大值為10000000,此處博主慫,不敢開二維怕崩,所以就採用一維。。。。不知有沒有壯士開二維過了。

完全揹包的狀態轉移方程:

d[i] = max(d[i],d[i-an]+an); //an代表硬幣面值,i代表湊得總錢數。

注意這裡的迴圈是從,i = an 到 i = sum。(why?見上面鏈結)

01揹包的狀態轉移方程:

d[i] = max(d[i],d[i-an]+an);

#include 

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long ll;

typedef

unsigned

long

long ull;

#define rep(idx1,num1) for(int idx1=0;idx1<(num1);idx1++)

#define pb push_back

#define empb emplace_back

#define mp make_pair

#define mem(s) memset(s,0,sizeof(s));

const

double eps = 1e-6;

const

int maxn = 100000 + 10;

int n,m;

int a[110],c[110];

int d[maxn];

int sum = 0;

//完全揹包

//an對應著硬幣面值,cnt對應著此面值的硬幣個數

void completebag(int an)

//01揹包

void zeroonebag(int an)

//二進位制優化

void change(int an,int cnt)

else

else}}

}int main()

for(int i = 1; i <= n; ++i)

mem(d);

if(sum > m) sum = m;

for(int i = 1; i <= n; ++i)

int ans = 0;

int kase[maxn];

//判斷出現了多少種面值

mem(kase);

kase[0] = 1;

for(int i = 1; i <= m; ++i)

}//cout << endl;

printf("%d\n",ans);

}return

0;}

HDU 2844 Coins 多重揹包

include include include include include using namespace std define clr c,v memset c,v,sizeof c const int inf 1 30 const int inf 1 30 const int m 1e5 1...

HDU 2844 Coins(多重揹包)

以前做題目光僅僅侷限於 0 1 揹包 和 完全揹包了。出來乙個 個數確定的揹包就不會了。看了網上的題解。原來是多重揹包。也就是說 用完全揹包和 0 1揹包混合求解的題目。應該是。對於 vi a i m 那麼就相當於乙個完全揹包。因為數量可以超過 最大限制。那麼就可以當做無限個使用。其他的 就需要二進...

hdu 2844 Coins 多重揹包

題意 給你一些不同價值和一定數量的硬幣,求用這些硬幣可以組合成價值在 1 m 之間的有多少 dp i 來表示容量為i這個包包可以裝多少價值,最後計數是要計價值和容量相等的個數 include include includeusing namespace std int sum,dp 100010 v...