MestInt gyakorlat visszalépéses keresés Probléma leírása N királynő probléma Az n királynő probléma, azt a kérdést veti fel, hányféleképpen lehet lerakni n darab királynőt egy n n-es táblán úgy, hogy a sakk szabályai szerint ne üssék egymást. Forráskód using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Nkirálynő class Program public class NKirálynő private int[] oszlopok; private int N; int megoldásokszáma; public NKirálynő(int királynőkszáma) N = királynőkszáma; oszlopok = new int[királynőkszáma]; private void KirálynőPozíció(int sor) if (jónaktűnő(sor)) if (sor == N - 1) //Eredmény kiíratása for (int i = 0; i < N; i++) oszlop"); Console.WriteLine(i + 1 + ".sor " + " " + (oszlopok[i]+1) + ". Console.WriteLine("------------------------------"); megoldásokszáma++; Console.WriteLine(); else for (int j = 0; j < N; j++) oszlopok[sor + 1] = j; KirálynőPozíció (sor + 1); private bool jónaktűnő(int index) int k = 0; bool jelölő = true; while (k < index && jelölő ) if ((oszlopok[index] == oszlopok[k]) (Math.Abs(oszlopok[index] - oszlopok[k]) == index - k)) jelölő = false; k++; return jelölő; public void királynőkelhelyezése() 1
// Az összes lehetséges eset feldolgozása for (int i = 0; i < N; i++) oszlopok[0] = i; KirálynőPozíció(0); Console.WriteLine("Megoldási lehetőségek száma: " + megoldásokszáma); static void Main(string[] args) int N = 8; NKirálynő királynők; királynők = new NKirálynő(N); Console.WriteLine(N +" kiránynő elhelyezése egy (" + N + " x " + N + ")-es sakktáblán" ); Console.WriteLine("A királynők elhelyezése: "); királynők.királynőkelhelyezése(); Console.ReadLine(); Feladat Módosítsa az előző feladatot úgy, hogy az előző n-királynő problémához hasonlóan, most úgynevezett szuperkirálynőket kell a táblára rakni. A szuperkirálynő léphet úgy, mint egy klasszikus sakkbeli királynő (vízszintes, függőleges, átlós), és tud ugrani, mint a huszár. 2
Hamilton kör Probléma leírása Definíció: Egy G gráfban Hamilton-körnek nevezünk egy kört, ha a gráf összes pontját tartalmazza. Egy utat Hamilton-útnak nevezünk, ha a gráf összes pontját tartalmazza. Felmerülő kérdések Adott egy G gráf. Hogyan dönthető el, hogy G-ben van-e Hamilton-kör? Ha van benne, hogyan található meg egy? Ha nincs, akkor mi akadályozza meg? https://www.cs.sunysb.edu/~skiena/combinatorica/animations/ham.html Egy útvonal nem Hamilton kör, - ha az összes N csúcson át vezető út után nem kerülünk vissza a kezdeti csúcsba, - ha bármely (0 < i < N) csúcsból nem vezet él útvonal[i-1] -ből útvonal[i] be, - ha az útvonal kört tartalmaz. Egyik él sem szerepelhet az útvonalban kétszer kivéve az elsőt és az utolsót. Reprezentáció - szomszédsági mátrix Legyen G=(V,E) véges gráf, és n a csúcsok száma. Ekkor a gráfot egy n x n es mátrixban ábrázoljuk, ahol az oszlopokat és a sorokat rendre a csúcsokkal indexeljük. Egy mezőben akkor van 1-es, ha a hozzá tartozó oszlop által meghatározott csúcs szomszédja a sor által meghatározott csúcsnak. Azaz pl. 0, ha (i, j) E A[i, j] = 1, ha (i, j) E Irányítatlan gráf esetén: 0 1 1 0 0 1 0 1 1 1 1 1 0 1 0 0 1 1 0 1 ( 0 1 0 1 0) Irányított gráf esetén: 0 1 1 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 ( 0 0 0 1 0) 3
Forráskód using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HamiltonKör class Program public class HamiltonBacktrack private int[][] M; private int[] útvonal; private int N; //a szomszédsági mátrix reprezentálásához //útvonal //csúcsok száma public HamiltonBacktrack(int[][] G) M = G; N = M.Length; útvonal = new int[n + 1]; private void hamilton(int index) if (jónaktűnő(index)) if (index == N -1) //Eredmény kiíratása lehetséges következő csúcs útvonal[index+1] = útvonal[0]; Console.WriteLine("Megoldás:"); for (int i = 0; i <= N; i++) Console.WriteLine(" " + útvonal[i]); Console.WriteLine("" ); else for (int j = 0; j < N; j++) útvonal[index+1] = j; hamilton(index+1); private bool jónaktűnő(int index) if (index == 0) return true; if (index == N - 1 && M[útVonal[index]][útVonal[0]] == 0) return false; if (index > 0 && M[útVonal[index - 1]][útVonal[index]] == 0) return false; int j = 0; while (j < index && útvonal[index]!= útvonal[j]) j++; return (j == index); public void hamiltonútvonal(int startcsúcs) útvonal[0] = startcsúcs; hamilton(0); static void Main(string[] args) int[][] Matrix = new int[4][]; Matrix[0] = new int[] 0, 1, 0, 1; Matrix[1] = new int[] 1, 0, 1, 0; Matrix[2] = new int[] 0, 1, 0, 1; Matrix[3] = new int[] 1, 0, 1, 0; Console.WriteLine("Hamilton kör"); Console.WriteLine("------------"); HamiltonBacktrack gráf; gráf = new HamiltonBacktrack(Matrix); 4 //kezdeti csúcs hozzáadása a végéhez //Az összes csúcs kipróbálása, mint
gráf.hamiltonútvonal(0); Console.ReadLine(); 5
0-1 Hátizsák probléma Probléma leírása Adott egy K kapacitású hátizsák (a turista egy bizonyos tömegnél nem tud többet elvinni), N darab tárgy, amelyek tömege m 1, m 2,...m N, értéke (hasznossága) pedig e 1, e 2, e n. Szeretnénk a legtöbb értéket bepakolni a hátizsákba, anélkül, hogy túllépnénk a hátizsák kapacitását. Ha az összes tárgy nem fér a hátizsákba akkor a turista kénytelen szelektálni és a válogatást úgy végzi, hogy a súlykorlátozás betartása mellett a magával vitt tárgyak összértéke (összhasznossága) minél nagyobb legyen. A válogatást tárgyanként egy vagy értéket felvehető döntési változóval írhatjuk le. Legyen a döntési változó a, amelynek értéke legyen, ha a -edik tárgyat a turista beteszi a hátizsákjába, ill. értéke legyen, ha a -edik tárgyat nem teszi be a hátizsákjába. A mutatja a hátizsákba behelyezett tárgyak összsúlyát, a pedig a hátizsákba behelyezett tárgyak összértékét. Így a fenti probléma matematikai megfogalmazása a következő: Adott a és a szám, amelyek pozitív egészek és. vektor -------------------------------------------------------------------------------------- K a hátizsák kapacitása értéksűrűség = e i/m i A tárgyakat ennek megfelelően csökkenő sorrendbe kell rendezni teljesméret= aktméret + k 1 j=i+1 m i maxlehetségesérték = aktérték + k 1 j=i+1 e i + (K teljesméret * (e k/m k) Tesztadatok: K = 16 n = 4 i e i m i e i/m i 1 45 Ft 3 15 Ft 2 30 Ft 5 6 Ft 3 45 Ft 9 5 Ft 4 10 Ft 5 2 Ft 6
Kezdetben: teljesméret = 0 + s1 + s2 = 0 + 3 + 5 = 8 maxlehetségesérték = 0 + v1 + v2 + (K teljesméret) * (e3/m3) = 0 + 45Ft + 30Ft + (16-8) * (5Ft) = 75Ft + 40Ft = 115Ft Következő szint? Forráskód using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication5 class Program public class HátizsákBacktrack private double maxérték; // A hátizsákba pakolható tárgyak maximális értéke... private double Kapacitás; //Hátizsák kapacitása... private double[] méretek; //Tárgyak méretei (növekvő sorendben kell megadni az értékeket) private double[] értékek; //Tárgyak értékei... private LinkedList<int> bepakolttárgyaklistája; //A belepakolt tárgyak listája... private int tárgyakszáma; //Tárgyak száma... public HátizsákBacktrack(double kapacitás, double[] méret, double[] érték, int tárgyaksz) maxérték = 0.0; Kapacitás = kapacitás; méretek = méret; értékek = érték; tárgyakszáma = tárgyaksz; bepakolttárgyaklistája = null; private void hátizsák(int index, double aktméret, double aktérték, LinkedList<int> aktlista) if (aktméret <= Kapacitás && aktérték > maxérték) maxérték = aktérték; LinkedList<int> bepakolttárgyaklistája = new LinkedList<int>(aktLista); if (jónaktűnő(index, aktméret, aktérték)) LinkedList<int> ballista = new LinkedList<int>(aktLista); LinkedListNode<int> csúcs = new LinkedListNode<int>(index + 1); bepakolttárgyaklistája = ballista; ballista.addlast(csúcs); hátizsák(index + 1, aktméret + méretek[index+1], aktérték + értékek[index+1], ballista); LinkedList<int> jobblista = new LinkedList<int>(aktLista); hátizsák(index + 1, aktméret, aktérték, jobblista); private bool jónaktűnő(int tárgy, double méret, double érték) double maxlehetségesérték = érték; double teljesméret = méret; int k = tárgy + 1; 7
Console.Write((tárgy + 1) +". lépés " + " " + méret + " " + érték + " ; " ); Console.WriteLine(""); if (méret > Kapacitás) return false; while (k < tárgyakszáma && teljesméret + méretek[k] <= Kapacitás) maxlehetségesérték += értékek[k]; teljesméret += méretek[k]; k++; if (k < tárgyakszáma) maxlehetségesérték += (Kapacitás - teljesméret) * (értékek[k] / méretek[k]); return maxlehetségesérték > maxérték; public void megoldáskeresése() LinkedList<int> aktlista = new LinkedList<int>(); hátizsák(0, 0.0, 0.0, aktlista); Console.WriteLine(" "); Console.WriteLine("Belepakolt elemek:"); for (int i = 0; i < bepakolttárgyaklistája.count(); i++) Console.WriteLine(" " + bepakolttárgyaklistája.elementat(i) + ". tárgy "); Console.WriteLine("A hátizsákba pakolható tárgyak értéke $" + maxérték); static void Main(string[] args) double[] Méretek = new double[4]; double[] Értékek = new double[4]; Méretek[0] = 3; Méretek[1] = 5; Méretek[2] = 5; Méretek[3] = 9; Értékek[0] = 45; Értékek[1] = 30; Értékek[2] = 10; Értékek[3] = 45; int Kapacitás = 16; int tágyakszáma = Értékek.Length; HátizsákBacktrack hátizsák; hátizsák = new HátizsákBacktrack(Kapacitás,Méretek,Értékek,tágyakSzáma); Console.WriteLine("Próbálkozások: "); Console.WriteLine("--------------------------------------"); hátizsák.megoldáskeresése(); Console.ReadLine(); Feladat: 8