Uproszczony Dyskretny problem plecakowy

VarrComodoo

Wizualizacja pozwalająca podglądać efekty działania swojego algorymu rozwiązującego zadania

***

Zadanie do rozwiązania:
Statek wycieczkowy zabiera na pokład co najwyżej m pasażerów. Na przystań
przyszło n rodzin liczących odpowiednio** k1, ..., kn,** członków. Poszczególne rodziny
chcą wejść w całości (wchodzi cała rodzina albo nikt). Skonstruuj rozwiązanie
zachłanne pomagające kapitanowi zabrać na pokład jak najwięcej osób. Oceń
złożoność i zilustruj działanie algorytmu dla samodzielnie wybranych danych.

pomocny link:
https://pl.m.wikipedia.org/wiki/Problem_plecakowy

Dla nowicjuszy zawsze pomocne może być zwizualizowanie efektów swoich prób, dlatego poniżej przedstawiam kod mogący być pomocnym przy podglądaniu swojego algorytmu rozwiązującego to zadanie.
Obecnie tylko dla zilustrowania co gdzie się dzieje, algorytm pakuje na statek cale rodziny ale przeważnei zostawia puste miejsca ;)

screenshot-20211127085615.png

Kod okna:

public partial class Form1 : Form
    {
        private Random rnd = new Random();
        private Upychacz pakowacz;
        private int zadanaPojemnoscStatku;
        private int zadanaLiczbaRodzin;

        private List<Rodzina> listaRodzinDoWejscia;
        private List<Rodzina> listaRodzinNaPokladzie;
        private List<Rodzina> listaRodzinaPozostawionych;
        
        private BindingSource bs_RodzinWej = new BindingSource();
        private BindingSource bs_RodzinNaPokladzie = new BindingSource();
        private BindingSource bs_RodzinPozostawionych = new BindingSource();

        public Form1()
        {
            InitializeComponent();
            listaRodzinDoWejscia = new List<Rodzina>();
            listaRodzinNaPokladzie = new List<Rodzina>();
            listaRodzinaPozostawionych = new List<Rodzina>();

            bs_RodzinWej.DataSource = listaRodzinDoWejscia;
        }

        private void btn_GenerujRodziny_Click(object sender, EventArgs e)
        {
            WyczyscStanAplikacji();

            int.TryParse(txtB_rodzinDoWejscia.Text, out zadanaLiczbaRodzin);
            for (int i = 0; i < zadanaLiczbaRodzin; i++)
                listaRodzinDoWejscia.Add(new Rodzina(rnd.Next(2,9)));

            WyswietlPodsumowanieRodzinNaWejsciu();
        }
        private void WyswietlPodsumowanieRodzinNaWejsciu()
        {
            lBox_RodzinyWPorcie.DataSource = bs_RodzinWej;
            bs_RodzinWej.ResetBindings(false);

            int liczbaOsob = 0;
            foreach (var item in listaRodzinDoWejscia)
                liczbaOsob += item.LiczbaOsobWRodzinie;

            lbl_OsobDoWejscia.Text = $"Łącznie {liczbaOsob} osób.";
        }
        private void btn_UstalPojemnoscstatku_Click(object sender, EventArgs e)
        {
            int.TryParse(txtB_PojemnoscStatku.Text, out zadanaPojemnoscStatku);
            label1.Text = $"Pojemnosc Statku: {zadanaPojemnoscStatku}osób";
        }

        private void btn_ZapakujNaStatek_Click(object sender, EventArgs e)
        {
            pakowacz = new Upychacz(zadanaPojemnoscStatku, listaRodzinDoWejscia);
            listaRodzinNaPokladzie = pakowacz.Zapakowani.OrderBy((x) => x.Nazwa).ToList();
            listaRodzinaPozostawionych = pakowacz.Pozostawieni.OrderBy((x) => x.Nazwa).ToList();
               
            WyswietlPodsumowanieZapakowania();
        }
        private void WyswietlPodsumowanieZapakowania()
        {
            bs_RodzinNaPokladzie.DataSource = listaRodzinNaPokladzie;
            lBox_RodzinyNaStatku.DataSource = bs_RodzinNaPokladzie;
            bs_RodzinNaPokladzie.ResetBindings(false);

            int osobNaPokladzie = 0;
            foreach (var item in listaRodzinNaPokladzie)
                osobNaPokladzie += item.LiczbaOsobWRodzinie;

            lbl_OsobNaStatku.Text = $"Łącznie {osobNaPokladzie} osob na statku.";

            bs_RodzinPozostawionych.DataSource = listaRodzinaPozostawionych;
            lBox_RodzinyKtoreNieWeszly.DataSource = bs_RodzinPozostawionych;
            bs_RodzinPozostawionych.ResetBindings(false);

            int osobPozostawionych = 0;
            foreach (var item in listaRodzinaPozostawionych)
                osobPozostawionych += item.LiczbaOsobWRodzinie;

            lbl_OsobPozostawionych.Text = $"Nie weszło łącznie {osobPozostawionych} osób.";
        }
        private void WyczyscStanAplikacji()
        {
            listaRodzinDoWejscia.Clear();
            lbl_OsobDoWejscia.Text = $"Łącznie X osób.";

            listaRodzinaPozostawionych.Clear();
            lbl_OsobPozostawionych.Text = $"Nie weszło łącznie X osób.";

            listaRodzinNaPokladzie.Clear();
            lbl_OsobNaStatku.Text = $"Łącznie X osob na statku.";

            WyswietlPodsumowanieZapakowania();

        }

obiekt "Rodzina":

public class Rodzina : IComparable
    {
        public string Nazwa { get; private set; }
        public int LiczbaOsobWRodzinie { get; private set; }

        public Rodzina(int liczbaOsob)
        {
            LiczbaOsobWRodzinie = liczbaOsob;
            Nazwa = NazywaczRodzin.NazwijRodzine(liczbaOsob);
        }

        public Rodzina(string nazwisko, int liczba)
        {
            this.Nazwa = nazwisko;
            this.LiczbaOsobWRodzinie = liczba;
        }

        public override string ToString()
        {
            return Nazwa;
        }

        public int CompareTo(object obj)
        {
            Rodzina rodz = obj as Rodzina;
            if (rodz!=null)
                return this.LiczbaOsobWRodzinie.CompareTo(rodz.LiczbaOsobWRodzinie);
            else
                throw new Exception("Błąd Rodzina: linia: 31");
        }
    }

obiekt "Upychacz":

public class Upychacz
    {

        private int dostepnaPojemnosc;
        private List<Rodzina> rodzinyDoZapakowania = new List<Rodzina>();

        public Upychacz(int zadanaPojemnosc, List<Rodzina> rodzinyDoUpchania)
        {
            dostepnaPojemnosc = zadanaPojemnosc;
            foreach (var item in rodzinyDoUpchania)
            {
                rodzinyDoZapakowania.Add(new Rodzina(item.Nazwa, item.LiczbaOsobWRodzinie));
            }
            Zapakowani = new List<Rodzina>();
            Pozostawieni = new List<Rodzina>();
            PakujTowarzystwo();
        }

        public List<Rodzina> Zapakowani { get; private set; }
        public List<Rodzina> Pozostawieni { get; set; }

        public void PakujTowarzystwo()
        {
            //To miejsce na osadzenie algorytmu pakujacego
            //rodzinyDoZapakowania.Sort();

            for (int i = rodzinyDoZapakowania.Count - 1; i >= 0; i--)
            {
                if (PoliczLudziW(Zapakowani) + rodzinyDoZapakowania[i].LiczbaOsobWRodzinie < dostepnaPojemnosc)
                {
                    Zapakowani.Add(rodzinyDoZapakowania[i]);
                    rodzinyDoZapakowania.RemoveAt(i);
                }
                else
                {
                    Pozostawieni.Add(rodzinyDoZapakowania[i]);
                    rodzinyDoZapakowania.RemoveAt(i);
                }
            }
        }


        private int LiczbaWolnychMiejscNaStatku()
        {
            return dostepnaPojemnosc - PoliczLudziW(Zapakowani);
        }

        private int PoliczLudziW(List<Rodzina> kolekcjaRodzin)
        {
            int wynik = 0;
            foreach (Rodzina item in kolekcjaRodzin)
                wynik += item.LiczbaOsobWRodzinie;
            return wynik;
        }
    }

i "nazywacz rodzin":

public static class NazywaczRodzin
    {
        private static int licznikNazw = 0;
        private static int surfiks = 1;
        private static char[] literki = new char[]   { 'A', 'B', 'C', 'D', 'E',
                                                       'F', 'G', 'H', 'I', 'J',
                                                       'K', 'L', 'M', 'N', 'O',
                                                       'P', 'Q', 'R', 'S', 'T',
                                                       'U', 'W', 'X', 'Y', 'Z' };

        public static string NazwijRodzine(int licznosc)
        {
            string nazwiskoRodziny = 
                $"Rodzina-{literki[licznikNazw].ToString()}{((surfiks != 1) ? surfiks.ToString() : "" )}__{licznosc}osobowa";

            if (licznikNazw % 24 == 0 && licznikNazw != 0)
            {
                surfiks++;
                licznikNazw = -1;
            }
            licznikNazw++;
            return nazwiskoRodziny;
        }
    }

0 komentarzy