Sikkələrin bir alt çoxluğunu seçməklə hansı cəmlərin əldə edilə biləcəyini müəyyən etməliyik. Hər bir sikkə:
istifadə edilməyə bilər;
yalnız bir dəfə istifadə edilə bilər.
Buna görə də bu Knapsack məsələsinin bir növüdür.
Bütün sikkələrin cəmi S = x_1 + x_2 + ... + x_n olsun. n \le 100 və x_i \le 1000 olduğundan, S \le 100000. Bu, hər bir mümkün cəm haqqında məlumatı saxlamağa imkan verir.
Aşağıdakı kimi təyin edək:
Başlanğıcda biz hələ heç bir sikkə istifadə etməmişik. cəmi həmişə əldə edilə bilər: dp[0] = 1. Bütün digər dəyərlər sıfırdır. Sürətləndirmək üçün -ni bitset şəklində saxlayacağıq.
Nominalı x_i olan hər bir sikkə üçün:
bitseti x_i mövqe sürüşdürürük;
nəticəni ilkin bitsetlə birləşdiririk:
-dan başqa qurulmuş bitlərin sayını hesablayırıq.
-dən -ə qədər olan cəmləri ardıcıl olaraq gəzib dp[s] = 1 olanları çap edirik.
Alqoritmin realizasiyası
bitsetində massivini saxlayacağıq.
#define MAX 100010
bitset<MAX> mask;Sikkələrin sayı -i oxuyuruq. dp[0] = 1 təyin edirik, çünki heç bir sikkə istifadə etmədən cəmi əldə edilə bilər.
scanf("%d", &n);
mask.set(0);dəyişənində bütün sikkələrin nominallarının cəmini hesablayırıq.
s = 0;Dövrdə bütün sikkələri ardıcıl olaraq emal edirik.
for (i = 0; i < n; i++)
{Nominalı olan sikkəni emal edirik.
scanf("%d", &w);
s += w;
mask |= (mask << w);
}Qurulmuş bitlərin sayını qaytarırıq. Lakin cəmi həmişə əldə edilə bildiyindən, onu istisna etmək lazımdır.
printf("%d\n", mask.count() - 1);Bütün əldə edilə bilən müsbət cəmləri çap edirik.
for (i = 1; i <= s; i++)
if (mask[i]) printf("%d ", i);
printf("\n");