Aladdinin bel çantası#1661

Aladdinin bel çantası (Həll təhlili)

Tutaq ki, dp_k[s] — yalnız ilk növ əşyadan istifadə etməyə icazə verildikdə, çəkisi -dən çox olmayan yükün maksimal dəyəridir.

Çəkisi olan yükü tərtib edərkən iki mümkün variantı nəzərdən keçirək:

dp_k[i] = dp_{k - 1}[i]
dp_k[i] = dp_k[i - w_k] + v_k.

Yükün dəyərini maksimuma çatdırmaq tələb olunduğundan, aşağıdakı rekurrent münasibəti alırıq:

dp_k[i] = max(dp_{k - 1}[i], dp_k[i - w_k] + v_k), w_k \le i \le s

Əsas hallar:

dp_0[i] = 0~v\ni~dp_k[0] = 0

Tutaq ki, f(k, s) funksiyası ilk növ əşyadan istifadə edərək, çəkisi -dən çox olmayan bel çantasına yığıla bilən yükün maksimal dəyərini hesablayır. Onda aşağıdakı rekurrent münasibət doğrudur:

f(k, s) = max(f(k - 1, s), f(k, s - w[k]) + v[k])

Qalır ki, f(k, s) funksiyasının qiymətini memoizasiya istifadə edərək hesablayaq.

Alqoritmin realizasiyası

İşçi massivləri elan edək:

#define MAXW 252
#define MAXN 37
int w[MAXN], p[MAXN];
int dp[MAXW];

Giriş məlumatlarını oxuyuruq.

scanf("%d %d", \&s, \&n);
for (i = 0; i \< n; i++)
  scanf("%d %d", \&w[i], \&p[i]);

növ əşyanı ardıcıl olaraq emal edirik.

for (k = 0; k \< n; k++)
{

növ əşyalardan istifadə etmə imkanını nəzərə alaraq, massivinin qiymətlərini yenidən hesablayırıq. Hər növ əşyanın sayı məhdudlaşdırılmadığından, hər əşya bir neçə dəfə seçilə bilər.

  for (i = w[k]; i \<= s; i++)
    dp[i] = max(dp[i], dp[i - w[k]] + p[k]);
}

Cavabı çap edirik.

printf("%d\n", dp[s]);

Alqoritmin realizasiyası — rekursiya

İşçi massivləri elan edək:

#define MAXW 252
#define MAXN 37
#define INF 2000000000
int w[MAXN], v[MAXN];
int dp[MAXN][MAXW];

f(k, s) funksiyası ilk növ əşyadan istifadə edərək, çəkisi -dən çox olmayan bel çantasına yığıla bilən yükün maksimal dəyərini hesablayır.

int f(int k, int s)
{

Əgər k = 0 və ya s = 0 olarsa, bel çantası boşdur və onun dəyəri -a bərabərdir.

  if (k == 0 || s == 0) return 0;

Əgər olarsa, biz icazə verilən çəkini aşmışıq və bu variantın mənası yoxdur. Buna görə qaytarırıq ( — müəyyən bir böyük ədəddir).

  if (s \< 0) return -INF;

Əgər f(k, s) qiyməti artıq hesablanıbsa, onu qaytarırıq.

  if (dp[k][s] != -1) return dp[k][s];

f(k, s) qiymətini hesablayırıq və onu dp[k][s]-də yadda saxlayırıq.

  return dp[k][s] = max(f(k - 1, s), f(k, s - w[k]) + v[k]);
}

Proqramın əsas hissəsi. Giriş məlumatlarını oxuyuruq.

scanf("%d %d", \&s, \&n);
for (i = 1; i \<= n; i++)
  scanf("%d %d", \&w[i], \&v[i]);

Cavabı hesablayır və çap edirik.

memset(dp, -1, sizeof(dp));
printf("%d\n", f(n, s));