Problem optymalizacyjny (cutting stock rod problem)

0

Siemka. Robię sobie ćwiczenie które jest wariantem "cutting stock rod problem" z algorytmów. Mam pobrać z linii poleceń cennik prętów (długość i cena) oraz projekt czyli zbiór odcinków prętów które mają zostać wykorzystane (wszystko posortowane rosnąco). Zadanie polega na takim doborze prętów z cennika aby zminimalizować odpad. Ilość prętów w cenniku jest nieograniczona. Wiem że najwydajniejszym sposobem jest wykonanie tego metodą programowania dynamicznego, ale na ten moment tego nie czaje. Robię to w inny sposób który teraz opiszę w punktach.

1.Generuję wszystkie możliwe podzbiory prętów z projektu takie w których suma elementów nie jest większa od najdłuższego pręta z cennika i zapisuje je w liście.
2.Tworzę tablicę w której zapisane są sumy elementów każdego z wygenerowanych zbiorów.
3.Tworzę metodę której przekazuję listę zbiorów i tablicę sum. W zewnętrznej iteruję po cenniku a w wewnętrznej po sumach. Wybieram najlepszy stosunek suma/pręt z cennika po czym kopiuję tablicę sum i listę podzbiorów i na tych kopiach wykonuję zerowanie wybranego ze stosunku suma/pręt z cennika elementu z tablicy sum i odpowiadających mu odcinków w liście podzbiorów. Wywołuję tę samą metodę pod koniec iteracji zewnętrznej pętli i przekazuje jej kopie sum i listę.Metoda jest zakończona gdy otrzyma wyzerowaną tablicę sum.

Wyobrażam sobie że ma to działać na takiej zasadzie że sprawdzę każdą możliwą kolejność wybierania prętów z cennika i dobiorę najlepsze zapełnienie które minimalizuje odpad.
Poniżej daję kod zakomentuję moment w którym wykryłem problem. Z góry dzięki za ewentualną pomoc lub sugestie co do metody rozwiązania.


public class Eco  {

    // List containing subsets generated based on set of rods in project.
    List<int[]> subSets=new ArrayList<>();

  




    private int[][] priceList;

  


     public Eco(int[] project,int[][] List){



         this.priceList=List;
         generateSubstets(project);

         List<int[]> sety=new ArrayList<>(this.subSets);

         int[] sums=new int[sety.size()];
         sums=setSums(sety,sums);
         recursion(sums,sety);
     }




        int powTwo (int n){

        int p=1;

        while (n-->0) p+=p;

            return p;

    }
        private void generateSubstets(int[] project){

        int n=project.length;
        int p=powTwo(n);

        int longestRod=priceList[0][priceList[0].length-1];



        int sum=0;



        for(int i=1;i<p;i++){


            int[] tab=new int[n];


            for (int j=0;j<n;j++){

                if((i & (1<<j))>0){




                    tab[j]=project[j];
                    sum=sum+project[j];






                }





            }

            if (!(sum>longestRod)) {

                subSets.add(tab);

            }
            sum=0;


        }





    }






    int[] setSums(List<int[]> sets,int[] tab){




        for (int j=0;j<tab.length;j++) {


            if (!(tab[j]==0)){
                tab[j]=0;
            }
            for (int i = 0; i <sets.get(0).length; i++) {

                tab[j]=tab[j]+sets.get(j)[i];

            }




        }


        return tab;

    }




    // Set new sums
    List<int[]> refreshSets (List<int[]> sets,int[] tab){



        for (int i=0;i<tab.length;i++){

            if(tab[i]>0){

                for (int[] temp:sets) {

                    temp[i]=0;
                    
                }
                
                
            }



        }

            return sets;
    }




    private void recursion(int [] tab,List<int[]> list) {

        if(!checkifNull(tab)){

            return;

        }




        double ratio;
        int index=0;

        for (int j = 0; j < priceList[0].length; j++) {

            ratio = 0;

// ratio ==0 zwróci jeśli obecny pręt z cennika jest niewystarczający do zapełnienia najmniejszej sumy z tablicy

            for (int i = 0; i < tab.length; i++) {


                if (ratio <= (double) tab[i] / priceList[0][j] & (double) tab[i] / priceList[0][j] <= 1.0 & (double) tab[i] > 0.0) {

                   ratio = (double) tab[i] / priceList[0][j];
                   index=i;



                }

            }




                if (ratio==0) continue;



                  System.out.println(ratio + " " + priceList[0][j] + " " + tab[index] +" "+ index);



                    int[] copy=new int[tab.length];
                    List<int[]> listcopy=new ArrayList<>(list);
                    System.arraycopy(tab,0,copy,0,tab.length);

                    // Tutaj jak wykona się pierwsze całkowite wyzerowanie 
                    // to metoda dalej już działa na wyzerowanej liście podzbiorów i tablicy, ale oryginale zmienne tab i list są ok.
                    // Podejrzewam że coś pomieszałem w rozumieniu przekazywania przez referencje.


                    listcopy=refreshSets(listcopy,listcopy.get(index));
                    copy=setSums(listcopy,copy);

                    recursion(Arrays.copyOf(copy,copy.length),new ArrayList<>(listcopy));



        }


     }




    boolean checkifNull(int[] tab){

        boolean check=false;

        for (int i=0;i<tab.length;i++){

            if(!(tab[i]==0)){

                check=true;

            }


        }

        return check;

    }

0

W "cutting stock rod", trak jak jest to rozwiązane, np. tutaj: https://www.geeksforgeeks.org/cutting-a-rod-dp-13/, dostajemy tablicę cen, dłudości mogą być dowolne (od 1 do n, i nie więcej niż długośc tablicy - bo to nie miałoby sensu), a zwracamy pojedynczą liczbę - maksymalną cenę jaką możemy uzyskać. Czy tak jest też u Ciebie? Opisz dokładnie, co ma być na wejściu, czego Spodziewasz się na wyjściu i Podaj rozwiązanie dla przykładowych danych.

0

Na wejściu daje cennik np.
4000 100
4500 160
10000 200

Pierwsza liczba to długość druga to cena.
I daje też projekt czyli odcinki prętów które mają być wykorzystane. Np.
200 200 350 350 350 600 1500 1500 3000 4500

Cennik zapisuje w tablicy dwuwymiarowej a projekt w jednowymiarowej.

Na wyjściu mam mieć pręt z cennika i odcinki z projektu na które został wykorzystany. Np.
4500 4500
4500 1500 3000
4000 200 200 350 350 350 600 1500
I to będzie najlepsze rozłożenie prętów odpad będzie miał długość 450. A jeszcze ważne że prętów z projektu nie można łączyć. Ja na razie mam tylko metodę która ma przejść po wszystkich możliwych sekwencjach doboru prętów z cennika i tam potem chce sobie zbudować coś z tego przez wybór najmniejszego odpadu. No ale to rekurencyjne przejście po tych sekwencjach mi nie wyszło za bardzo .

0

Zrobić to dla każdej pary (długość - cena) z wejścia?

Czy rozwiązanie: [200 200 350 350 350 600 1500] to rozwiązanie dla 4000, wzięte z tego: [200 200 350 350 350 600 1500 1500 3000 4500]? A nie powinno być: [1500, 1500, 350, 350, 200]?

0

No to jest jedna z możliwości rozłożenia prętów dająca najmniejszy odpad. Może być ich więcej które dadzą taki sam końcowy odpad

0

ALe podałem Ci ciąg prętów, dla którego odpad jest 100.

1 użytkowników online, w tym zalogowanych: 0, gości: 1