da Esame di Programmazione Luglio 2005 TESTO

da Esame di Programmazione Luglio 2005
TESTO
Esercizio 2 (punti 20 in prima approssimazione)
Si tratta di dettagliare a livello di pseudo codice un algoritmo ad alto livello per il problema
di trovare un abbinamento stabile (stable matching).
Questo problema è interessante perchè la sua soluzione costituisce la base per la soluzione
di problemi quali: il miglior modo di gestire l'abbinamento studenti-aziende per tirocini,
oppure abbinare persone che cercano lavoro ed aziende che cercano personale,....
Il problema in forma stilizzata.
Abbiamo un insieme U = {u1 , u2 , ...,un} di uomini e D= {d1 , d2 , ...,dn} di donne; notare che gli
insiemi hanno lo stesso numero di elementi.
Cascun uomo ha una sua graduatoria per D (graduatoria, in ordine di preferenza,
completa, nel senso che copre tutto D, e senza ex aequo); analogamente ogni donna ha
una sua graduatoria per U.
Un abbinamento è un insieme A di coppie di UxD, tale che ogni u di U ed ogni w di W
compare una ed una sola volta (in altre parole, A è una funzione bigettiva da U in D).
Dato un abbinamento A, se A contiene due coppie (u, d) e (u', d') tali che u preferisce d'
e d' preferisce u (cioè: d' precede d nella graduatoria di u e u precede u' nella
graduatoria di d' ) allora abbiamo una instabilità: è ragionevole che u e d' abbandonino il
partner e formino una nuova coppia.
Quello che si vuole è un abbinamento che non contenga instabilità, detto abbinamento
stabile.
Con le condizioni dette sopra su U, D e le graduatorie, il problema ammette soluzione
sempre ed esistono algoritmi per trovarne una. L'algoritmo che vediamo è il più antico
(anni 60) ed ha taglio e risultati maschilisti ...
Algoritmo di Gale-Shapley
•
All'inizio tutti gli u in U sono liberi e tutte le d in D sono libere.
•
Ciclo:
se ci sono uomini liberi allora
si sceglie un uomo libero, sia u
sia d la donna che è prima nella graduatoria di u tra quelle a cui u non ha
ancora fatto proposte
se d è libera allora si forma la coppia (u, d)
altrimenti d è già in coppia con u' :
se d preferisce u' ad u, allora u rimane libero e d resta con u';
se invece d preferisce u, allora u' diventa libero e si forma la nuova
coppia (u, d)
•
All'uscita dal ciclo, l'insieme delle coppie correnti fornisce un abbinamento stabile
1
Scopo dell'esercizio è specificare meglio l'algoritmo:
• precisando le strutture dati necessarie per memorizzare U, D, le graduatorie, le coppie
già formate e quant'altro serve;
• precisando come si sceglie u, come si trova d eccetera
L'algoritmo che dovete scrivere voi deve essere strutturato come segue:
•
•
•
da un file DATI, si leggono i dati (cioè: U, D, e le graduatorie) e si memorizzano;
ciclo ........ ; nel ciclo, una volta scelto u, tutto il resto deve essere fatto tramite una o
piu' procedure/funzioni;
all'uscita del ciclo, si stampano, in qualche ordine, le coppie dell'abbinamento
ottenuto.
Non si possono usare "variabili globali". I passaggi di dati tra main e procedure e
funzioni devono avvenire tramite parametri e il risultato delle funzioni.
Si possono usare procedure / funzioni ausiliarie.
L'enfasi è sulla struttura piu' che sui dettagli ! Non perdere tempo a dettagliare: apertura
file, formato nelle istruzioni di input / output, .... ed altri aspetti di poco conto.
Domande
a) Come si rappresentano i dati nel file ?
Se non trovo la risposta non correggo il resto.
b) Precisare le strutture dati principali usate nell'algoritmo.
Se non trovo la risposta non correggo il resto. ?
c) Scrivere, usando lo pseudo-codice utilizzato nelle dispense, oppure il C, l'algoritmo
completo, commentando, quando necessario.
2
SOLUZIONE
Parte a)
Per i dati scelgo la codifica piu' compatta, quindi uomini e donne sono rappresentati da
numeri da 1 a n
Formato del file DATI:
1a riga :
il numero n
le n righe seguenti si riferiscono, nell'ordine, a u1 , u2 , ...,un ; ciascuna di queste righe è una
successione di numeri, che rappresentano la graduatoria;
ad esempio con n=3
2a riga
3 1 2
3a riga
3 2 1
4a riga
2 3 1
quindi la graduatoria di
u1
è d3 , d1 , d2
le n righe seguenti si riferiscono alle donne e sono analoghe
Suppongo che l'input rispetti le regole.
Parte b)
type
dando direttamente le dichiarazioni di tipo e commentandole
Uomo = record
end
grad : array[ 1 .. n ] of integer
prima : integer
partner : integer
(i valori vanno da 1 a n)
(vedi sotto)
(vedi sotto)
prima e` un indice che "punta" nell'array grad; all'inizio prima = 1, man mano che
l'uomo fa proposte, l'indice viene incrementato ...
partner: se è 0, indica "libero", altrimenti contiene il partner corrente
type
Donna
= record
end
grad : array[ 1 .. n ] of integer
partner : integer
qui non serve un campo
Inoltre uso
(i valori vanno da 1 a n)
(come sopra)
prima
U : array [1 .. n] of Uomo
D : array [1 .. n] of Donna
dove la posizione individua la persona: quindi U[1] è il record di u1 ...........
Per quanto riguarda l'accoppiamento corrente, cioè l'insieme delle coppie già formate:
l'informazione è contenuta nell'array U (ed anche in D);
quindi, alla fine basta scorrere uno dei due array per produrre l'output.
3
Parte c)
Algoritmo in pseudo codice
qui dettaglio tutto, ma non era richiesto .....
var
n : integer
DATI : File
leggi n dal file DATI
{
blocco con dichiarazioni:
i tipi Uomo e Donna, i due array U e D
la procedura cerca
(vedi sotto)
variabili ausiliarie : k, j , finito,....
inizializzazioni e letture:
per k = 1, 2, ..., n :
{ U[k].partner <--- 0 ; U[k].prima <--- 1;
D[k].partner <--- 0 }
per k = 1, 2, ..., n :
per j = 1, 2, ...n : leggi da DATI U[k].grad[j]
per k = 1, 2, ..., n :
per j = 1, 2, ...n : leggi da DATI D[k].grad[j]
ciclo:
finito <--- falso
while (not finito) do {
scelgo il primo uomo libero partendo dall'alto
per k = 1, 2, ..., n :
if U[k].partner = 0 then break
if k > n then finito <--- vero
else
}
cerca (U, D, k)
fine del ciclo
per k = 1, 2, ...,n :
}
vedi sotto
ora leggendo i partner degli uomini ho il risultato:
scrivi ("coppia : uomo :" , k, " donna : " , U[k].partner, "a capo")
fine del blocco e del programma
4
procedura cerca (
UU : array [1 .. n] of Uomo IN-OUT
DD : array [1 .. n] of Donna IN-OUT
kk : integer IN
{
var
valore compreso tra 1 ed n
)
jj , uu, prima : integer
prima <--- UU[kk].prima
jj <--- UU[kk].grad [prima]
uu <--- DD[jj].partner
if uu = 0 then { DD[jj].partner <--- kk ; UU[kk]. partner <--- jj }
else
{
per ii = 1, 2, ..., n :
if DD[jj].grad[ii] = uu or DD[jj].grad[ii] = kk
then break
notare che senza dubbio trovero` uno o l'altro ....
if
DD[jj].grad[ii] = kk
then
{
cioè lei preferisce il nuovo arrivato
DD[jj].partner <--- kk ; UU[kk]. partner <--- jj
UU[uu].partner <--- 0
}
UU[kk].prima ++
}
5