Saturday, December 21, 2013

Split the set of numbers into subsets

 Разбить множество чисел на подмножества, разница сумм которых минимальна и вывести на экран эту разницу.
Для решения этой задачи будем использовать динамическое программирование.
Не сложно понять, что сумма каждого из двух выбранных множеств должна быть как можно "ближе" к половине суммы всего исходного множества т.е. если представить сумму всего исходного множества за C, а суммы двух выбранных подмножеств за A и B, то:
A + B = C;
A ~ C / 2
B ~ C / 2
И так, задача сводится к нахождению подмножества с суммой C/2.
Почитайте это

Перейдём к реализации.


Так как каждую вещь можно брать только один раз, то будем идти не слева направо, а справа налево.

Будем хранить 1 или 0, что значит можно ли достичь суммы M, если взять N предметов.

0 <= M <= C/2

Ответом будет ячейка таблицы отмеченная как 1 и с максимальной M (т.к. нам нужно взять набранную сумму как можно ближе к C/2)


  1. #include <iostream>
  2. #include <vector>
  3. #include <cmath>
  4. #define REP(i,n) for (int i = 0; i < n; i++)
  5. using namespace std;
  6. bool f[100];
  7. int main()
  8. {
  9. int n;
  10. long sum = 0;
  11. cin >> n;
  12. vector<int> v(n);
  13. REP(i,n) cin >> v[i], sum += v[i];
  14. int m = sum/2;
  15. int w = 0;
  16. f[0] = 1;
  17. for (int i = n-1; i >= 0; i--)
  18. {
  19. for (int j = m; j >= 0; j--)
  20. {
  21. if (f[j] == 1)
  22. {
  23. f[j+v[i]] = 1;
  24. }
  25. }
  26. }
  27. for (int i=m;i>=0;i--) if (f[i]) {
  28. w=i;
  29. break;
  30. }
  31. cout << abs(w-(sum-w)) << endl;
  32. return 0;
  33. }