Sunteți pe pagina 1din 9

Note de laborator Specializare

Algoritmi si structuri de date 2 Info 1

Laborator 4
Descriere: Metoda Greedy –2

1. Decriere formala

Un algoritm greedy construieste solutia pas cu pas. Initial, multimea candidatilor selectati este vida.
La fiecare pas, ıncercam sa adaugam la aceasta multime pe cel mai promitator candidat, conform
functiei de selectie. Daca, dupa o astfel de adaugare, multimea de candidati selectati nu mai este
fezabila, eliminam ultimul candidat adaugat;acesta nu va mai fi niciodata considerat. Daca, dupa
adaugare, multimea de candidati selectati este fezabila, ultimul candidat adaugat va ramane de
acum incolo ın ea. De fiecare data cand largim multimea candidatilor selectati, verificam daca
aceasta multime nu constituie o solutie posibila a problemei. Daca algoritmul greedy functioneaza
corect, prima solutie gasita va fi totodata o solutie optima a problemei.

Solutia optima nu este ın mod necesar unica: se poate ca functia obiectiv sa aiba aceeasi valoare
optima pentru mai multe solutii posibile.

Descrierea formala a unui algoritm greedy general este:

function greedy(C) // C este multimea candidatilor


S←∅ // S este multimea ın care construim solutia
while not solutie(S) and C ≠ ∅ do
x ← un element din C care maximizeaza/minimizeaza select(x)
C ← C − {x}
if fezabil(S ∪ {x}) then S ← S ∪ {x}

if solutie(S) then return S


else return ”nu exista solutie”

2. Problema comis voiajorului

Un comis voiajor trebuie sa viziteze mai multe sedii aflate in orase diferite cu un efort minim.
Datele de intrare vor fi salvate intr-un fisier DateComisVoiajor.in cu urmatoarea structura: pe
prima linie numarul total de orase, iar pe urmatoarele linii indexul orasului urmat de perechi de
valori reprezentand legaturile cu celalalte orase si costurile acestor legaturi.

5
0 1 5 2 1 3 9 4 3
1 2 3 3 7 4 2
2 3 8 4 4
3 4 2

Initial el se va afla in orasul notat cu 1. El nu doreste sa treaca de doua ori prin acelasi oras, iar la
intoarcere vrea sa revina in orasul 1. Cunoscand legaturile existente intre orase, sa se gaseasca cel
mai scurt drum care ii permite comis voiajorului viziteze toate orasele cu un efort minim.

Pentru datele de intrare de mai sus, solutia este (1,3) (3,2) (2,5) (5,4) (4,1), iar lungimea drumului
este 17.
ASD

import java.util.*;
import java.io.*;

public class ComisVoiajor{

private int valori[][]; // Distantele dintre sedii


private int solutie[][]; // Vectorul solutie
private int cost;
private int nrSedii=0; // Numarul de sedii
private static final int infinit = 10000;

public void citireFisier(String numeFisier){


BufferedReader br;
StringTokenizer st;
String linie;
boolean linia1 = true;

try{
br = new BufferedReader(new FileReader(numeFisier));

while((linie = br.readLine()) != null){


st = new StringTokenizer(linie, " \r\n\t");

if(linia1){
nrSedii = Integer.parseInt(st.nextToken());
valori = new int[nrSedii][nrSedii];
solutie = new int[nrSedii][nrSedii];

// Se initializeaza cu 0 matricea cu distante. Va fi drum intre


// doua sedii i si j daca valori[i][j] = valori[j][i] != 0
for(int i = 0; i < nrSedii; i++)
for(int j = 0; j < nrSedii; j++)
valori[i][j] = solutie[i][j] = 0;
linia1 = false;
continue;
}
else{
int i, j;

// S-a citit o linie care incepe cu un sediu i urmat de sediile j


// care sunt legate de sediul i. Dupa fiecare sediu j urmeaza distanta
// de la i la j
i = Integer.parseInt(st.nextToken());
while(st.hasMoreTokens()){
j = Integer.parseInt(st.nextToken());
valori[i][j] = valori[j][i] = Integer.parseInt(st.nextToken());
}
}
}
}catch(Exception e){
System.out.println("Eroare I/O" + e.getMessage());
}
}

public void greedy(){


int i, j, k, p, ni, minim, drum[][];

drum = new int[nrSedii][nrSedii];

for(i = 0; i < nrSedii; i++)


for(j = 0; j < nrSedii; j++)
drum[i][j] = 0;
ASD

ni = 0;
drum[ni][ni] = cost = i = p = 0;

for(k = 0; k < nrSedii - 1; k++){


minim = infinit;

for(j = 0; j < nrSedii; j++)


if((valori[i][j] < minim) && (drum[i][j] == 0) && (valori[i][j] != 0)){
minim = valori[i][j];
p = j;
}

solutie[i][p] = valori[i][p];
cost += valori[i][p];
drum[i][p] = drum[p][i] = 1;
i = p;
}

cost += valori[p][ni];
solutie[p][ni] = valori[p][ni];
}

public void afisare(){


System.out.println("Solutia:\n");
String sir = "Drumul ales:\n";

for(int i = 0; i < nrSedii; i++)


for(int j = 0; j < nrSedii; j++)
if(solutie[i][j] != 0)
sir += "(" + (i+1) + ", " + (j+1) + ") = " + solutie[i][j] + "\n";
sir += "Distanta parcursa: " + cost;

System.out.println(sir);
}

public static void main(String []args) {


ComisVoiajor cv = new ComisVoiajor();
cv.citireFisier("DateComisVoiajor.in");
cv.greedy();
cv.afisare();
}
}

3. Problema spectacolelor

Într-o sală, într-o zi, trebuie planificate n spectacole. Pentru fiecare spectacol se ştie intervalul în
care se desfăşoară: [oraInceput, oraSfarsit]. Se cere să se planifice un număr maxim de spectacole
astfel încât să nu se suprapună. Datele de intrare sunt salvate intr-un fisier si au urmatoare structura:
pe prima linie numarul de spectacole ce trebuie programate, pe a doua linie intervalul orar in care
se pot programa spectacole, iar pe urmatoarele n linii intervalul in care se desfasoara fiecare
spectacol.

9
10 22
11 12
11 13
11 14
12 15
16 17
13 18
16 20
18 20
19 22
ASD

import java.io.*;
import java.util.*;

public class Spectacole{

private int nrSpec, ora1, ora2, oraInceput[], oraSfarsit[];


private String sir="";

public void citireFisier(String numeFisier){


BufferedReader bf;
StringTokenizer st;
String linie;
boolean linia1 = false, linia2 = false;
int i = 0;

try{
bf = new BufferedReader(new FileReader(numeFisier));

while((linie = bf.readLine()) != null){


st = new StringTokenizer(linie, " \t\n\r");

if(!linia1){
nrSpec = Integer.parseInt(st.nextToken());
oraInceput = new int[nrSpec];
oraSfarsit = new int[nrSpec];
linia1 = true;
continue;
}

if(!linia2){
ora1 = Integer.parseInt(st.nextToken());
ora2 = Integer.parseInt(st.nextToken());
linia2 = true;
continue;
}

while(st.hasMoreTokens())
{
oraInceput[i++] = Integer.parseInt(st.nextToken());
oraSfarsit[i-1] = Integer.parseInt(st.nextToken());
}
}
}catch(Exception e)
{
System.out.println("Eroare " + e.getMessage());
}
}

public void sortare(){

boolean sortat;
int tempI;
int tempS;

do{
sortat = true;
for(int i = 0; i < nrSpec - 1; i++)
if(oraSfarsit[i] > oraSfarsit[i+1]){
tempI = oraInceput[i];
tempS = oraSfarsit[i];

oraInceput[i] = oraInceput[i+1];
oraSfarsit[i] = oraSfarsit[i+1];
ASD

oraInceput[i+1] = tempI;
oraSfarsit[i+1] = tempS;

sortat = false;
}
}while(!sortat);
}

public void greedy(){

sir = "Cea mai buna solutie (intre orele " + ora1 + " si " + ora2 + "):\n";

sir += oraInceput[0] + "\t" + oraSfarsit[0] + "\n";

int i = 1;
int ultimaOra = oraSfarsit[0];

for(i = 1; i < nrSpec; i++)


for(int j = i; j < nrSpec; j++)
if(oraInceput[j] >= ultimaOra){
sir += oraInceput[j] + "\t" + oraSfarsit[j] + "\n";
ultimaOra = oraSfarsit[j];
i = j;
break;
}

System.out.println(sir);
}

public static void main(String []args){


Spectacole s = new Spectacole();

s.citireFisier("DateSpectacole.in");
s.sortare();
s.greedy();
}
}

4. Problema discreta a rucsacului

Fiind date n obiecte, fiecare cu greutatea g[i] si valoarea v[i] si un rucsac cu capacitatea totala gt, sa
se determine ce obiecte trebuie selectate pentru a fi luate in rucsac astfel incat greutatea lor totala sa
nu depaseasca gt si valoarea lor sa fie maxima. Datele de intrare vor fi preluate dintr-un fisier
rucsac.in. Fisierul are urmatoarea structura: pe prima linie numarul de obiecte, pe a doua linie
greutatea totala a rucsacului si pe urmatoarele linii perechi de valori reprezentand greutatea si
valoarea fiecarui obiect in parte.

5
22
7 13
10 5
8 8
2 12
9 7

import java.util.*;
import java.io.*;

public class ProblemaRucsacului{


private int valoriVolum[], valoriCost[], nrObiecte, volumTotal;
ASD

private double profit[];


private String sir;

public void citireFisier(String numeFisier){


BufferedReader br;
StringTokenizer st;
String linie;
boolean linia1 = false, linia2 = false;
int i = 0;

try{
br = new BufferedReader(new FileReader(numeFisier));

while((linie = br.readLine()) != null){


st = new StringTokenizer(linie, " \t\n\r");

if(!linia1){
nrObiecte = Integer.parseInt(st.nextToken());
valoriVolum = new int[nrObiecte];
valoriCost = new int[nrObiecte];
profit = new double[nrObiecte];
linia1 = true;
continue;
}

if(!linia2){
volumTotal = Integer.parseInt(st.nextToken());
linia2 = true;
continue;
}

while(st.hasMoreTokens()){
valoriVolum[i++] = Integer.parseInt(st.nextToken());
valoriCost[i-1] = Integer.parseInt(st.nextToken());
profit[i-1] = (double)valoriCost[i-1]/(double)valoriVolum[i-1];
}
}
}catch(Exception e){
System.out.println("Eroare " + e.getMessage());
}
}

public void sortare(){

boolean sortat;
int tempV;
int tempC;
double tempProfit;

do{
sortat = true;
for(int i = 0; i < nrObiecte - 1; i++)
if(profit[i] < profit[i+1]){
tempProfit = profit[i];
tempV = valoriVolum[i];
tempC = valoriCost[i];

profit[i] = profit[i+1];
valoriVolum[i] = valoriVolum[i+1];
valoriCost[i] = valoriCost[i+1];

profit[i+1] = tempProfit;
valoriVolum[i+1] = tempV;
valoriCost[i+1] = tempC;
ASD

sortat = false;
}
}while(!sortat);
}

public void greedy(){


int copieV = volumTotal;
int cost = 0;

sir = "Cea mai buna solutie de umplere a rucsacului:\n";

for(int i = 0; i < nrObiecte; i++){


if(valoriVolum[i] <= volumTotal){
sir += "Obiect de volum " + valoriVolum[i] + " si cost "
+ valoriCost[i] + "\n";

volumTotal -= valoriVolum[i];
cost += valoriCost[i];
}
}

sir += "Volumul umplut: " + (copieV - volumTotal) + " Cost: " + cost;

System.out.println(sir);
}

public static void main(String []args){


ProblemaRucsacului pr = new ProblemaRucsacului();

pr.citireFisier("DateRucsacDiscret.in");
pr.sortare();
pr.greedy();
}
}

5. Plate sumei

Se dau suma s si n tipuri de monede si bancnote , avand valori de v1,v2,.....,vn € . Se cere o


modalitate de plata a sumei s utilizand aceste monede si bancnote. Fisierul de intrare are
urmatoarea structura. Pe prima linie numarul de bancnote diferite, pe a doua linie suma de plata si
pe urmatoarele linii valoarea fiecarei bancnote si cantitatea disponibila.

7
3827
50 10
100 5
200 2
500 50
50 2
10 17
1 100

import java.io.*;
import java.util.*;

public class PlataSuma{


private int valori[], numarBancnote[], nrValori, sumaTotala;
private String sir;

public void citireFisier(String numeFisier){


BufferedReader bf;
ASD

StringTokenizer st;
String linie;
boolean linia1 = false, linia2 = false;
int i = 0;

try{
bf = new BufferedReader(new FileReader(numeFisier));

while((linie = bf.readLine()) != null){


st = new StringTokenizer(linie, " \t\n\r");

if(!linia1){
nrValori = Integer.parseInt(st.nextToken());
valori = new int[nrValori];
numarBancnote = new int[nrValori];
linia1 = true;
continue;
}

if(!linia2){
sumaTotala = Integer.parseInt(st.nextToken());
linia2 = true;
continue;
}

while(st.hasMoreTokens()){
valori[i++] = Integer.parseInt(st.nextToken());
numarBancnote[i-1] = Integer.parseInt(st.nextToken());
}
}
}catch(Exception e)
{
System.out.println("Eroare " + e.getMessage());
}
}

public void sortare(){


boolean sortat;
int tempV, tempN;

do{
sortat = true;
for(int i = 0; i < nrValori - 1; i++)
if(valori[i] < valori[i+1]){
tempV = valori[i];
tempN = numarBancnote[i];

valori[i] = valori[i+1];
numarBancnote[i] = numarBancnote[i+1];

valori[i+1] = tempV;
numarBancnote[i+1] = tempN;

sortat = false;
}
}while(!sortat);
}

public void greedy(){


int nr, copieSuma = sumaTotala;

sir = new Integer(sumaTotala).toString() + " = ";

for(int i = 0; i < nrValori; i++){


nr = sumaTotala/valori[i];
ASD

if(nr >= numarBancnote[i])


nr = numarBancnote[i];
if(nr > 0){
if(sumaTotala < copieSuma)
sir += " + ";

sir += nr + "*" + valori[i];

sumaTotala -= nr*valori[i];
}
}
System.out.println(sir);
}

public static void main(String []args){


PlataSuma ps = new PlataSuma();

ps.citireFisier("DatePlataSuma.in");
ps.sortare();
ps.greedy();
}
}

6. Exercitii

6.1 Insulele unui arhipelag sunt conectate prin poduri. Un turist isi propune sa viziteze aceste
insule, o singura data , pornind de la o anumita insula . Pozitia podurilor este data sub forma unei
matrici care este salvata intr-un fisier aflat pe disc. Fiecare pod are de asemenea asociata o anumita
lungime. Sa se afiseze solutia optima de vizitare a tuturor insulelor arhipelagului.

6.2 Săritura calului

Se dă o tablă de şah N x N. Determinati un drum de lungime minima pe care il poate parcurge un


cal pe o tabla de sah intre doua pozitii date (daca exista). La fiecare pas se alege acel camp din care
avem cele mai putine mutari mai departe (exista totusi o mutare).

6.3 Problema colorării hărţilor

Sunt date N ţări precizându-se relaţiile de vecinătate. Se cere să se determine o posibilitate de


colorare a hărţii (cu cele n ţări) astfel încât să nu existe două ţări vecine colorate la fel.

S-ar putea să vă placă și