public class Banka {
// Nominalne hodnoty jednotlivych druhov CP
private int[] hodnotyCP;
// Pole, do ktoreho si budeme zapamatavat uz vypocitane riesenia
// podproblemov
private int[] cache;
/**
* Metoda, ktora vrati minimalny pocet CP pre zadanu sumu s pouzitim
* memoizacie
*/
private int minPocetCP(int suma) {
// Zaporne cislo - nie je co riesit...
if (suma < 0)
return -1;
// Ak sme uz optimalne vyplatenie sumy suma pocitali, vratime rovno to,
// co mame v poli cache
if (cache[suma] != Integer.MIN_VALUE) {
return cache[suma];
}
// Ak je suma 0, optimalny pocet je 0 - trivialny pripad
if (suma == 0)
return 0;
// Najdeme minimalny pocet CP tak, ze vyberieme taky typ CP, po ktoreho
// odratani dostaneme sumu, ktoru mozno vyplatit s najmensim poctom
// papierov.
int minimum = Integer.MAX_VALUE;
for (int i = 0; i < hodnotyCP.length; i++) {
int pom = minPocetCP(suma - hodnotyCP[i]);
// Specialne riesime, ked nam volanie vratilo -1. To hovori, ze sumu
// (suma - hodnotyCP[i]) nemozno vobec vyplatit. Pri hladani minima
// uvazujeme len sumy, ktore vyplatit mozno.
if (pom != -1) {
if (pom < minimum) {
minimum = pom;
}
}
}
// Finalny vysledok je -1 (ak ziadnu z "mensich" nemozno vyplatit) alebo
// 1+min (na zaklade rekurzivneho vzorceka)
int vysledok;
if (minimum == Integer.MAX_VALUE)
vysledok = -1;
else
vysledok = 1 + minimum;
// Pred vratenim vysledku, vysledok ulozime do cache
cache[suma] = vysledok;
return vysledok;
}
/**
* Vrati minimalny pocet CP s pouzitim memoizacie
*/
public int minVyplatenie(int suma) {
cache = new int[suma + 1];
minPocetCP(suma);
return cache[suma];
}
/**
* Riesenie ulohy dynamickym programovanim, kedy si obsah pola cache
* systematicky vypocitame.
*/
public int minVyplatenieDynamicky(int suma) {
// Trivialny pripad
cache[0] = 0;
// Postupne vyplname policka pola cache od 1 po suma...
for (int s = 1; s < cache.length; s++) {
// Odsimulujeme spravanie rekurzivnej implementacie s memoizaciou
int minimum = Integer.MAX_VALUE;
for (int i = 0; i < hodnotyCP.length; i++) {
int pom;
// Nahrada: int pom = minPocetCP(suma - hodnotyCP[i]);
if (s - hodnotyCP[i] >= 0) {
// Namiesto rekurzivneho volania hodnotu rovno vytiahneme z
// cache
pom = cache[s - hodnotyCP[i]];
} else {
pom = -1;
}
if (pom != -1) {
if (pom < minimum) {
minimum = pom;
}
}
}
int vysledok;
if (minimum == Integer.MAX_VALUE)
vysledok = -1;
else
vysledok = 1 + minimum;
// Namiesto vratenia hodnoty len
cache[s] = vysledok;
}
return cache[suma];
}
public Banka(int[] hodnotyCP) {
this.hodnotyCP = hodnotyCP.clone();
}
public static void main(String[] args) {
Banka statnaPokladnica = new Banka(new int[] { 100, 500, 800, 20, 50,
30, 10, 5, 25, 1, 2, 3, 10 });
System.out.println(statnaPokladnica.minVyplatenieDynamicky(10000000));
}
}