Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 1049 Solved: 605
Description
給你N顆寶石,每顆寶石都有重量和價值。要你從這些寶石中選取一些寶石,保證總重量不超過W,且總價值最大爲,並輸出最大的總價值。數據範圍:N<=100;W<=2^30,並且保證每顆寶石的重量符合a*2^b(a<=10;b<=30)
Input
輸入文件中包含多組數據。每組數據的格式如下:第一行是兩個正整數n和W,1≤n≤100,1≤W≤2^30,分別表示寶石的數目和最多能帶走的寶石重量。接下來的n行,每行有兩個正整數weighti和valuei,1≤weighti≤2^30, 0≤valuei≤2^30,分別表示第i顆寶石的重量和價值,且保證weighti能寫成a*2^b(1≤a≤10,0≤b≤30)的形式。同一行的兩個正整數之間用空格隔開。最後一組數據的後面有兩個-1,表示文件的結束。這兩個-1並不代表一組數據,你不需對這組數據輸出結果。並且輸入文件中數據的組數不超過20。
Output
對於輸入的每組數據,輸出一個整數C,表示小P最多能帶走的寶石的總價值。每個結果整數C單獨佔一行,且保證C不會超過2^30。
Sample Input
4 10
8 9
5 8
4 6
2 5
4 13
8 9
5 8
4 6
2 5
16 75594681
393216 5533
2 77
32768 467
29360128 407840
112 68
24576 372
768 60
33554432 466099
16384 318
33554432 466090
2048 111
24576 350
9216 216
12582912 174768
16384 295
1024 76
-1 -1
Sample Output
14
19
1050650
HINT
Source
dalao講解
這就是神奇的分層揹包???
我們的狀態設計爲:
…………數位爲 9876543210
舉個例子 M = 1101010101
則dp[i][j]表示容量爲
dp[5][3]表示M爲110101時的情況
這樣定義之後我們先按照一層一層地DP,把每一層,也就是i相同的情況DP出來,存在dp[i][j]中,注意這個時候dp[i][j]只表示了
因此我們在層與層之間處理的時候
top表示m的最大位是第幾位
第一層for i 1 top
第二層for j 1000 0
第三層for k 0 j
dp[i][j] = max(dp[i][j], dp[i][ j - k ] + dp[ i - 1 ][ 2 * k + ( m >> ( i - 1 ) ) & 1 ] )
因爲我的j是逆序for j的,因此每次用到的情況都是沒有用到後面狀態的,也即每次都是隻是
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
const int MAXM = 35;
int n, m, cnt[MAXN];
long long dp[MAXM][MAXN];
int main( ) {
while( scanf( "%d%d", &n, &m ) && n != -1 && m != -1 ) {
long long ans = 0;
memset( dp, 0, sizeof(dp) );
for( register int i = 1; i <= n; i++ ) { int w, v, c = 0;
scanf( "%d%d", &w, &v );
while( w % 2 == 0 ) w /= 2, c++;
for( register int j = 1000; j >= w; j-- )
dp[c][j] = max( dp[c][ j - w ] + v, dp[c][j] );
cnt[c] += w;
}
int top = 0;
for( register int i = m; i; i >>= 1 ) top++; top--;
for( register int i = 1; i <= top; i++ ) {
for( register int j = 1000; j >= 0; j-- )
for( register int k = 0; k <= j; k++ )
dp[i][j] = max( dp[i][j], dp[i][ j - k ] + dp[ i - 1 ][ min( 1000, ( k * 2 ) + ( m >> ( i - 1 ) & 1 ) ) ] );
}
printf( "%lld\n", dp[top][1] );
}
return 0;
}