Redistribuer les ressources équitablement

Redistribuer les ressources équitablement - Divers - Programmation

Marsh Posté le 28-02-2011 à 01:35:20    

Bonjour,
je souhaite redistribuer les ressources que chacun détient équitablement.
 
j'ai un ensemble d'individu (nom, somme) et je dois trouver la liste des dont à faire pour qu'au final tous les individus possède la même somme.
 
Merci de votre contribution.


Message édité par Profil supprimé le 28-02-2011 à 10:14:05
Reply

Marsh Posté le 28-02-2011 à 01:35:20   

Reply

Marsh Posté le 28-02-2011 à 13:53:23    

Tu autorises des sommes de type "float"? parce que pour déterminer la somme à obtenir, suffit de faire la somme des Somme / nb d'individus.
 
Après, un algo d'ordonnancement basé sur LPT : je classerais les individus par rapport à la moyenne obtenue pour savoir s'ils vont donner ou recevoir. Classement dans l'ordre décroissant de la somme pouvant être donnée ou à recevoir.
Ensuite, une boucle sur les individus donnant :
tant qu'un individu peut donner, lui prendre le max(ce qu'il peut donner;ce que l'individu doit recevoir pour atteindre la moyenne). Si l'individu n'a pas assez à donner, passer au suivant pour compléter ce qu'il faut à celui qui reçoit.
Si l'individu recevant a assez reçu, passer au suivant en prenant au donneur courant
fin de boucle.
 
Un truc de ce genre devrait le faire, non?
 
ps : si tu travailles qu'avec des nb entiers, là, ça peut être plus chaud déjà... ca voudra aussi dire que tous n'auront pas exactement la même somme ou alors, tu refuses de traiter le cas si la moyenne obtenue n'est pas entière...

Message cité 2 fois
Message édité par rufo le 28-02-2011 à 13:54:40

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 28-02-2011 à 13:56:53    

rufo a écrit :

Tu autorises des sommes de type "float"? parce que pour déterminer la somme à obtenir, suffit de faire la somme des Somme / nb d'individus.
 
Après, un algo d'ordonnancement basé sur LPT : je classerais les individus par rapport à la moyenne obtenue pour savoir s'ils vont donner ou recevoir. Classement dans l'ordre décroissant de la somme pouvant être donnée ou à recevoir.
Ensuite, une boucle sur les individus donnant :
tant qu'un individu peut donner, lui prendre le max(ce qu'il peut donner;ce que l'individu doit recevoir pour atteindre la moyenne). Si l'individu n'a pas assez à donner, passer au suivant pour compléter ce qu'il faut à celui qui reçoit.
Si l'individu recevant a assez reçu, passer au suivant en prenant au donneur courant
fin de boucle.
 
Un truc de ce genre devrait le faire, non?
 
ps : si tu travailles qu'avec des nb entiers, là, ça peut être plus chaud déjà... ca voudra aussi dire que tous n'auront pas exactement la même somme ou alors, tu refuses de traiter le cas si la moyenne obtenue n'est pas entière...


 
Ca doit être mieux que ce que j'ai fait jusqu'à présent.
 
Merci, je vais implémenter et tester.  :jap:

Reply

Marsh Posté le 28-02-2011 à 14:40:11    

[:darkmavis] Ca fonctionne nikel. Merci rufo.


Message édité par Profil supprimé le 28-02-2011 à 14:40:19
Reply

Marsh Posté le 28-02-2011 à 16:03:00    

Pas de quoi... ;) Par curiosité, t'avais fait quoi comme algo initialement?


Message édité par rufo le 28-02-2011 à 16:03:16

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 28-02-2011 à 16:28:36    

Alors, j'affecte pas le système immédiatement, au lieu, je construit un tableau de donations à effectuer.
 
En partant avec un tableau de Users trier dans l'ordre croissant.
 

Code :
  1. procedure Balance(Users     : in Users_Table;
  2.      Donations : out Donations_Access) is
  3.     Total_Sum : Float := Total(Users);
  4.     Equi_Sum : Float := Total_Sum/Float(Users'Length);
  5.     Donate : Float;
  6.     Temp : Donations_Access;
  7.  begin
  8.     for Index in reverse Users'Range loop
  9.        exit when Users(Index).Sum < Equi_Sum;
  10.        Donate := Users(Index).Sum - Equi_Sum;
  11.        while Donate > 0.0 loop
  12.           for Ki in 1..Index-1 loop
  13.              if Users(Ki).Sum < Equi_Sum then
  14.                 if Donations = null then
  15.                    Temp := new Donations_Table(1..1);
  16.                    Create(Temp(1),
  17.                           Users(Index).Id,
  18.                           Users(Ki).Id,
  19.                           Equi_Sum - Users(Ki).Sum);
  20.                 else
  21.                    Temp := new Donations_Table(1..Donations'Length + 1);
  22.                    Create(Temp(Temp'length),
  23.                           Users(Index).Id,
  24.                           Users(Ki).Id,
  25.                           Equi_Sum - Users(Ki).Sum);
  26.                 end if;
  27.                 Donate := Donate - (Equi_Sum - Users(Ki).Sum);
  28.                 Free(Donations);
  29.                 Donations := Temp;
  30.              end if;
  31.              New_Line;
  32.           end loop;
  33.        end loop;
  34.     end loop;
  35. end Balance;


 
 
Le tiens donne ceci dans le même langage.
 

Code :
  1. procedure Balance(Users     : in Users_Table;
  2.                  Donations : out Donations_Access) is
  3.   Donators : Users_Table(Users'Range);
  4.   recipients : Users_Table(Users'Range);
  5.   Donator, recipient : natural := 0;
  6.   Total_Sum : Float := Total(Users);
  7.   Equi_Sum : Float := Total_Sum/Float(Users'Length);
  8.   Receive, Donate : Float := 0.0;
  9.   Temp : Donations_Access;
  10.  
  11. begin
  12.   for Index in Users'Range loop
  13.      if (Users(Index).Sum > Equi_Sum) then
  14.         Donators(Donator + 1) := Users(Index);
  15.         Donator := Donator + 1;
  16.      else
  17.         Recipients(Recipient + 1) := Users(Index);
  18.         Recipient := Recipient + 1;
  19.      end if;
  20.   end loop;
  21.   for Index in reverse 1..Donator loop
  22.      Donate := Donators(Index).Sum - Equi_Sum;
  23.      while Donate > 0.0 loop
  24.         for Ki in reverse 1..Recipient loop
  25.  
  26.            if (Donate >= (Equi_Sum - Recipients(Ki).sum)) then
  27.               Receive := Equi_Sum - Recipients(Ki).Sum;
  28.               Donate := Donate - (Equi_Sum - Recipients(Ki).Sum);
  29.               Recipient := Recipient - 1;
  30.            else
  31.               Receive := Donate;
  32.               Donate := 0.0;
  33.            end if;
  34.            if (Donations = null) then
  35.               Temp := new Donations_Table(1..1);
  36.               Create(Temp(1),
  37.                      Donators(Index).Id,
  38.                      Recipients(Ki).Id,
  39.                      receive);
  40.            else
  41.               Temp := new Donations_Table(1..Donations'Length + 1);
  42.               Create(Temp(Temp'length),
  43.                      Donators(Index).Id,
  44.                      Recipients(Ki).Id,
  45.                      Receive);
  46.               Temp(1..Donations'Length) := Donations.all;
  47.            end if;
  48.            Free(Donations);
  49.            Donations := new Donations_Table ' (Temp.all);
  50.         end loop;
  51.      end loop;
  52.   end loop;
  53. end Balance;

Reply

Marsh Posté le 28-02-2011 à 16:56:35    

Je demandais pas le code, juste l'algo (le principe auquel t'avais pensé)... Parce que retrouver l'algo à partir du code, c'est pas évident... :/


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 28-02-2011 à 17:10:15    

L'idée générale était de trier le tableau en croisant ou décroissant, peut importe avec Ada, j'ai reverse;
et du donner au plus pauvre à partir du plus riche. j'usqu'à ce que les deux index ce rencontre au centre avec des somme égale à n -1
 
partir du début ou la fin donc; pour parcourir avec Index, le tableau d'users
   affecter donation avec users(index).somme - moyenne
   tant que donation > 0.0; -- je travail avec des float donc.
       parcourir avec Ki, le tableau users dans e sens inverse de index.
          si users(Ki).somme < moyenne alors
              affecter user(Ki).somme avec moyenne - users(Ki).somme
              soustraire moyenne - users(Ki).somme à donation;
          fin si
        fait;
    fait.
fait.
 

Reply

Marsh Posté le 28-02-2011 à 18:47:48    

Mon implementation à pas l'air de fonctionner parfaitement en fait.
J'avais testé sur 4 item, mais là sur 70 c'est pas les bon résultat.
 
Le premier et le dernier users


Id  : Toto 1
Sum :  1.00000E+03
Id  : Toto 70
Sum :  7.00000E+04


Le premier et le dernier dons


Source : Toto 70
Target : Toto 35
Sum    :  5.00000E+02
Source : Toto 36
Target : Toto 1
Sum    :  0.00000E+00


Le premier et le dernier users après les dons


Id  : Toto 1
Sum :  1.00000E+03
Id  : Toto 70
Sum :  3.55000E+04


 
Donc, il y a un problème.


Message édité par Profil supprimé le 28-02-2011 à 18:48:04
Reply

Marsh Posté le 28-02-2011 à 19:38:48    

J'ai vu où est le problème.
 
Ben non, pouratnt, c'est pas ça... Heu !


Message édité par Profil supprimé le 28-02-2011 à 19:40:59
Reply

Marsh Posté le 28-02-2011 à 19:38:48   

Reply

Marsh Posté le 28-02-2011 à 21:13:24    

En fait je crois que j'éssaie de résoudre un cas particulier pour cette méthode.
Elle marche que sur les premiers rang.
Après faux entrer quelque chose de plus aléatoire. Que de 1 à N attribuer N à somme initiale.
 
Voil alors, j'ai fais avec un générateur aléatoire, ça fonctionne après l'introduction d'un variable supplémentaire pour soustraire le reste de don à la somme devant être théoriquement perçu.
En fin ça c'est dans mon cas, qui doit effectuer les donation à par la suite.
 
Voici mon code actuel.
 

Code :
  1. procedure Balance(Users     : in Users_Table;
  2.                  Donations : out Donations_Access) is
  3.   Donators : Users_Table(Users'Range);
  4.   recipients : Users_Table(Users'Range);
  5.   Donator, recipient : natural := 0;
  6.   Total_Sum : Float := Total(Users);
  7.   Equi_Sum : Float := Total_Sum/Float(Users'Length);
  8.   Rest, Receive, Donate : Float := 0.0;
  9.   Temp : Donations_Access;
  10.  
  11. begin
  12.   New_Line;
  13.   Put("Total :" );
  14.   Put(Total_Sum);
  15.   New_Line;
  16.   Put("Midle :" );
  17.   Put(Equi_Sum);
  18.  
  19.   for Index in Users'Range loop
  20.      if (Users(Index).Sum >= Equi_Sum) then
  21.         Donators(Donator + 1) := Users(Index);
  22.         Donator := Donator + 1;
  23.      elsif (Users(Index).Sum < Equi_Sum) then
  24.         Recipients(Recipient + 1) := Users(Index);
  25.         Recipient := Recipient + 1;
  26.      end if;
  27.   end loop;
  28.  
  29.   for Index in reverse 1..Donator loop
  30.  
  31.      Donate := Donators(Index).Sum - Equi_Sum;
  32.  
  33.      while Donate > 0.0 loop
  34.  
  35.         for Ki in reverse 1..Recipient loop
  36.  
  37.            receive := (Equi_Sum - Recipients(Ki).Sum) - rest;
  38.  
  39.            if (Donate >= receive) then
  40.  
  41.               Donate := Donate - Receive;
  42.               Recipient := Recipient - 1;
  43.               Rest := 0.0;
  44.               Free(Temp);
  45.  
  46.               if (Donations = null) then
  47.  
  48.                  Temp := new Donations_Table(1..1);
  49.                  Create(Temp(1),
  50.                         Donators(Index).Id,
  51.                         Recipients(Ki).Id,
  52.                         receive);
  53.               else
  54.  
  55.                  Temp := new Donations_Table(1..Donations'Length + 1);
  56.                  Create(Temp(Temp'length),
  57.                         Donators(Index).Id,
  58.                         Recipients(Ki).Id,
  59.                         Receive);
  60.                  Temp(1..Donations'Length) := Donations.all;
  61.               end if;
  62.               Free(Donations);
  63. Donations := new Donations_Table ' (Temp.all);
  64.            elsif Donate > 0.0 then
  65.               Receive := Donate;
  66.               if Recipients(Ki).Sum + Rest + Donate = Equi_Sum then
  67.                  Rest := 0.0;
  68.               else
  69.                  Rest := Rest + Donate;
  70.               end if;
  71.               Donate := 0.0;
  72.  
  73.               Free(Temp);
  74.  
  75.               if (Donations = null) then
  76.  
  77.                  Temp := new Donations_Table(1..1);
  78.                  Create(Temp(1),
  79.                         Donators(Index).Id,
  80.                         Recipients(Ki).Id,
  81.                         receive);
  82.               else
  83.  
  84.                  Temp := new Donations_Table(1..Donations'Length + 1);
  85.                  Create(Temp(Temp'length),
  86.                         Donators(Index).Id,
  87.                         Recipients(Ki).Id,
  88.                         Receive);
  89.                  Temp(1..Donations'Length) := Donations.all;
  90.               end if;
  91.  
  92.               Free(Donations);
  93.  
  94.               Donations := new Donations_Table ' (Temp.all);
  95.  
  96.               exit;
  97.            end if;
  98.         end loop;
  99.      end loop;
  100.   end loop;
  101. end Balance;


 
Et- encore ça fait pas l'équilibre exact en fait.


Message édité par Profil supprimé le 28-02-2011 à 23:17:48
Reply

Marsh Posté le 01-03-2011 à 00:01:47    

Sur 100_000 users ça fait un sacré écart tout de même, quand ça veux bien fonctionner.
 

First and last users :
 
Id  : Toto 1
Sum :  7.81541E+00
Id  : Toto 100000
Sum :  3.07765E+06
Sort users...
Balancing system
 
Total : 2.49722E+11
Midle : 2.49722E+06
First and last donations :
 
Source : Toto 99846
Target : Toto 39811
Sum    :  1.20000E+01
Source : Toto 50710
Target : Toto 7869
Sum    :  9.92500E+01
Donate all donations...
 
First and last users :
 
Id  : Toto 7869
Sum :  1.92386E+06
Id  : Toto 99846
Sum :  2.49723E+06
Check Min and Max user sum :
 
Min : 1.92386E+06
Max : 2.49723E+06

Reply

Marsh Posté le 01-03-2011 à 09:34:33    

T'as peut-être un pb d'arrondi des nombres, parce que là, tu bosses avec de très grands nombres. Regardes si avec 50 users et des sommes allant de 1 à 100 (par ex), si l'algo fonctionne. Si oui, alors c'est qu'il est bon et que ton pb vient du stockage des grands nbs...


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 01-03-2011 à 10:50:39    

Bonjour rufo,
 
Effectivement, sur un petit nombre d'users et des sommes raisonnables, les écart sont moins grand, voir nul.
 
De plus si je ne m'abuse, il n'y a d'écart qu'entre le plus petit et le plus grand élément, tous les autre sont égaux.
 
Mais le programme plante tout de même 3 fois sur 4.


Message édité par Profil supprimé le 01-03-2011 à 10:51:05
Reply

Marsh Posté le 01-03-2011 à 11:11:31    

C'est quand même bizarre :/ On sait établir avec précision la somme cible (la moyenne des sommes de chaque utilisateur). Donc après en classant le groupe des donneurs (au-dessus de la moyenne) et de le groupe des receveurs (en-dessous de la moyenne) dans l'ordre décroissant de leur écart à la moyenne (en valeur absolue) puis en parcourant le groupe des donneurs pour alimenter le groupe des receveurs, j'ai du mal à comprendre pourquoi ça ne marche pas :??:
 
T'as bien pris en compte qu'un donneur continue de donner tant qu'il n'est pas arrivé à un écart de 0 à la moyenne et qu'un receveur continue de recevoir également tant que son écart à la moyenne n'est pas arrivé à 0?


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 01-03-2011 à 11:19:22    

Reply

Marsh Posté le 01-03-2011 à 11:39:57    

Ca, ça donne une explication à son pb avec de très grands nbs. Mais ça ne répond pas à la question pour l'algo que j'ai proposé semble ne pas fonctionner...


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 01-03-2011 à 11:59:09    

Qu'est ce qui ne fonctionne pas  ? Parce que les deux seuls moments où tu évoque un algo, tu as une somme et une moyenne à chaque fois :
 

rufo a écrit :

Tu autorises des sommes de type "float"? parce que pour déterminer la somme à obtenir, suffit de faire la somme des Somme / nb d'individus.
 
...


 

rufo a écrit :

C'est quand même bizarre :/ On sait établir avec précision la somme cible (la moyenne des sommes de chaque utilisateur). Donc après en classant le groupe des donneurs (au-dessus de la moyenne) et de le groupe des receveurs (en-dessous de la moyenne) dans l'ordre décroissant de leur écart à la moyenne (en valeur absolue) puis en parcourant le groupe des donneurs pour alimenter le groupe des receveurs, j'ai du mal à comprendre pourquoi ça ne marche pas :??:


 
Tu parles de classement, et donc de comparaison, sur tes résultats. Normal que ça pète...
 

Reply

Marsh Posté le 01-03-2011 à 14:42:11    

Bon, ben j'ai implémenté mon algo, pour 200 users et une somme par utilisateur allant de 1 à 1000, ça marche.


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 03-03-2011 à 06:36:44    

rufo a écrit :

Bon, ben j'ai implémenté mon algo, pour 200 users et une somme par utilisateur allant de 1 à 1000, ça marche.


 
Je suis bien contant pour toi.  :sweat:

Reply

Marsh Posté le 03-03-2011 à 09:42:07    

Pour toi, avec 200 users et une somme par user allant de 1 à 1000, ça marche pas? Si c'est le cas, je peux te filer mon code (en php).


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 03-03-2011 à 09:57:24    

Bonjour rufo,
 
Pour une somme de 5 à 1000 sur 200 users, ça marche.
 
(comment fais-tu pour commencer à 1 et finir à 1000 sur 200 users ?)
 
En php, non ça me dit rien.  :o  
Merci.
 
Je regarderais pourquoi mon code fonctionne pas à tout les coup.
Je vous tiens au courant.


Message édité par Profil supprimé le 03-03-2011 à 09:57:38
Reply

Marsh Posté le 03-03-2011 à 11:22:58    

j'initialise la somme aléatoirement entre 1 et 1000 pour chacun des 200 users...


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 03-03-2011 à 11:25:16    

Ok, c'est à peu près ce que je faisais.
 
Avec 10_000 users dans les même condition financière, chez toi, ça fonctionne ?


Message édité par Profil supprimé le 03-03-2011 à 11:25:33
Reply

Marsh Posté le 03-03-2011 à 13:46:49    

oui (et c'est super rapide en +)


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 03-03-2011 à 18:34:15    

Ok !
Donc, pour 10_000 users, moi ça plante carrément.
 
Finalement rufo, Je bien mater ton code PHP ou un pseudo code un peu plus poilu.

Reply

Marsh Posté le 04-03-2011 à 10:14:16    

Voici mon code, fait l'autre jour entre 12h00 et 14h00, vite fait pour vérifier si mon algo marchait ou pas...

Code :
  1. <?php
  2. define('NB_USERS', 200);
  3. define('MIN_SUM', 1);
  4. define('MAX_SUM', 1000);
  5. define('NB_ROUND', 2);
  6. define('AttrSum', 'Sum');
  7. define('AttrDist', 'Dist');
  8.  
  9. function sortList($List, $Flag)
  10. {
  11.     foreach($List as $k => $Row)
  12.     {
  13.         $Sums[$k] = $Row[AttrSum];
  14.         $Dists[$k] = $Row[AttrDist];
  15.     }
  16.  
  17.     array_multisort($Dists, $Flag, SORT_NUMERIC, $Sums, SORT_ASC, $List);
  18.  
  19.     return $List;
  20. }
  21.  
  22. $Avg = 0;
  23.  
  24. // Init users with a sum
  25. $ArrayUsers = array();
  26. for($u = 0; $u < NB_USERS; $u++)
  27. {
  28.     $ArrayUsers["u$u"][AttrSum] = rand(MIN_SUM, MAX_SUM);
  29.     $ArrayUsers["u$u"][AttrDist] = 0;
  30.     $Avg += $ArrayUsers["u$u"][AttrSum];
  31. }
  32.  
  33. // Compute the AVG
  34. $Avg = round($Avg / NB_USERS, NB_ROUND);
  35.  
  36. $ArrayGifts = array();
  37.  
  38. // Compute distance to the AVG
  39. echo "AVG = $Avg<br />\n";
  40.  
  41. $ArrayDonors = array();
  42. $ArrayReceivers = array();
  43. foreach($ArrayUsers as $u => $User)
  44. {
  45.     $ArrayUsers[$u][AttrDist] = $User[AttrSum] - $Avg;
  46.     if ($ArrayUsers[$u][AttrDist] >= 0)
  47.     {
  48.         $ArrayDonors[$u] = $ArrayUsers[$u];
  49.         echo "User $u owns ".$User[AttrSum].", so he can give ".$ArrayUsers[$u][AttrDist]."<br />\n";
  50.     }
  51.     else
  52.     {
  53.         $ArrayReceivers[$u] = $ArrayUsers[$u];
  54.         echo "User $u owns ".$User[AttrSum].", so he MUST GET ".$ArrayUsers[$u][AttrDist]."<br />\n";
  55.     }
  56. }
  57.  
  58. // Sort DESC of the 2 arrays
  59. $ArrayDonors = sortList($ArrayDonors, SORT_DESC);
  60.  
  61. // Negative values!!!
  62. $ArrayReceivers = sortList($ArrayReceivers, SORT_ASC);
  63.  
  64. $ArrayKeysReceivers = array_keys($ArrayReceivers);
  65. $CurrentReceiver = 0;
  66. $ReceiversSize = count($ArrayReceivers);
  67.  
  68. foreach($ArrayDonors as $d => $Donor)
  69. {
  70.     while($ArrayDonors[$d][AttrDist] > 0)
  71.     {
  72.         if ($CurrentReceiver >= $ReceiversSize)
  73.         {
  74.              // Stop while and foreach
  75.              break 2;
  76.         }
  77.  
  78.         $GiftValue = min($ArrayDonors[$d][AttrDist], abs($ArrayReceivers[$ArrayKeysReceivers[$CurrentReceiver]][AttrDist]));
  79.  
  80.         // User (0) gives to user (1), the value (2)
  81.         $ArrayGifts[] = array($d, $ArrayKeysReceivers[$CurrentReceiver], $GiftValue);
  82.  
  83.         // Give
  84.         $ArrayDonors[$d][AttrSum] -= $GiftValue;
  85.         $ArrayDonors[$d][AttrDist] -= $GiftValue;
  86.  
  87.         // Receive
  88.         $ArrayReceivers[$ArrayKeysReceivers[$CurrentReceiver]][AttrSum] += $GiftValue;
  89.         $ArrayReceivers[$ArrayKeysReceivers[$CurrentReceiver]][AttrDist] += $GiftValue;
  90.  
  91.         // Need other gifts?
  92.         if ($ArrayReceivers[$ArrayKeysReceivers[$CurrentReceiver]][AttrDist] >= 0)
  93.         {
  94.             // Go to the next receiver
  95.             $CurrentReceiver++;
  96.         }
  97.     }
  98. }
  99.  
  100. echo "<br />\n-------------------------------Results---------------------------<br />\n";
  101. foreach($ArrayGifts as $g => $Gift)
  102. {
  103.     echo "User ".$Gift[0]." (".$ArrayDonors[$Gift[0]][AttrSum]." ) gives to user ".$Gift[1]." the gift of ".$Gift[2]." (".$ArrayReceivers[$Gift[1]][AttrSum]." )<br />\n";
  104. }
  105. ?>


Message édité par rufo le 04-03-2011 à 10:17:54

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 04-03-2011 à 10:17:49    

Merci rufo
 
For()
   While()
 
 
T'as que deux boucles. J'en ai trois, ça fais une de trop. Je vais potasser.

Reply

Marsh Posté le 04-03-2011 à 15:59:29    

Bon, ça ça fonctionne. Merci encore rufo !  [:pingouinator]
 
Maintenant ça marche sur 10_000 et ça marche plus sur 100_000  :fou:


Message édité par Profil supprimé le 04-03-2011 à 16:10:18
Reply

Marsh Posté le 04-03-2011 à 17:26:36    


 
Le for -> parcours des donneurs
Le while -> tant que le donneur peu donner aux receveurs


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 04-03-2011 à 19:14:07    

Merci encore rufo.
 
Alors, c'est bizarre... Ca marche pour 50_000 pour une somme aléatoire et une somme fixe.
 
Mais pour 100_000 j'ai un écart conséquant, peut-être pas à tout les coup, mais c'est pas normal.
 
Mon code avec Ada :
J'avais oublié le reverse, parce que mes tableaux sont trier dans l'ordre croissant.
De plus, comme je n'effectue pas les donation immédiatement, j'ai une variable rest en plus.

Code :
  1. procedure Balance(Users     : in Users_Table;
  2.                     Donations : out Donations_Access) is
  3.      Donators : Users_Table(Users'Range);
  4.      recipients : Users_Table(Users'Range);
  5.      Donator, Recipient : Long_Long_integer := 0;
  6.      Total_Sum : Float := Total(Users);
  7.      Equi_Sum : Float := Total_Sum/Float(Users'Length);
  8.      Rest, Receive, Donate : Float := 0.0;
  9.      Temp : Donations_Access;
  10.  
  11.   begin
  12.      
  13.      for Index in Users'Range loop
  14.         if (Users(Index).Sum > Equi_Sum) then
  15.            Donators(Donator + 1) := Users(Index);
  16.            Donator := Donator + 1;
  17.         elsif (Users(Index).Sum < Equi_Sum) then
  18.            Recipients(Recipient + 1) := Users(Index);
  19.            Recipient := Recipient + 1;
  20.         end if;
  21.      end loop;
  22.  
  23.  Main:
  24.      for Index in reverse 1..Donator loop
  25.         Donate := Donators(Index).Sum - Equi_Sum;
  26.         while Donate > 0.0 loop
  27.            if Recipient < 1 then
  28.               exit Main;
  29.            end if;
  30.  
  31.            receive := (Equi_Sum - Recipients(Recipient).Sum) - rest;
  32.  
  33.            if (Donate >= receive) then
  34.               Donate := Donate - receive;
  35.               Free(Temp);
  36.               if (Donations = null) then
  37.  
  38.                  Temp := new Donations_Table(1..1);
  39.                  Create(Temp(1),
  40.                         Donators(Index).Id,
  41.                         Recipients(Recipient).Id,
  42.                         receive);
  43.               else
  44.  
  45.                  Temp := new Donations_Table(1..Donations'Length + 1);
  46.                  Create(Temp(Temp'length),
  47.                         Donators(Index).Id,
  48.                         Recipients(Recipient).Id,
  49.                         Receive);
  50.                  Temp(1..Donations'Length) := Donations.all;
  51.               end if;
  52.               Free(Donations);
  53.               Donations := new Donations_Table ' (Temp.all);
  54.               Recipient := Recipient - 1;
  55.               Rest := 0.0;
  56.            elsif Donate > 0.0 then
  57.               Rest := Rest + Donate;
  58.               Receive := Donate;
  59.               Donate := 0.0;
  60.               Free(Temp);
  61.               if (Donations = null) then
  62.  
  63.                  Temp := new Donations_Table(1..1);
  64.                  Create(Temp(1),
  65.                         Donators(Index).Id,
  66.                         Recipients(Recipient).Id,
  67.                         receive);
  68.               else
  69.                  Temp := new Donations_Table(1..Donations'Length + 1);
  70.                  Create(Temp(Temp'length),
  71.                         Donators(Index).Id,
  72.                         Recipients(Recipient).Id,
  73.                         Receive);
  74.                  Temp(1..Donations'Length) := Donations.all;
  75.               end if;
  76.               Free(Donations);
  77.               Donations := new Donations_Table ' (Temp.all);
  78.            end if;
  79.         end loop;
  80.      end loop Main;
  81.   end Balance;

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed