給你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...