/*************************************************************************************************************************************/ /* */ /* C O M B I N A I S O N S D E Q U A T R E N O M B R E S : */ /* */ /* */ /* Author of '$xtc/combinaisons.01$vv$c' : */ /* */ /* Jean-Francois COLONNA (LACTAMME, 20140704120117). */ /* */ /*************************************************************************************************************************************/ #include "INCLUDES.01.I" extern double pow(); #define RESULTAT_ATTENDU \ 24 #define nNOMBRES \ 4 enum ListeDesNombres { N1=1 ,N2=3 ,N3=4 ,N4=6 }; typedef struct { int Numerateur; int Denominateur; } Fraction; /* Definition d'une fraction (nombre rationnel). */ #define UNITE \ 1 #define Numer(fraction) \ (fraction.Numerateur) #define Denom(fraction) \ (fraction.Denominateur) #define EGAL(fraction,numerateur,denominateur) \ { \ Numer(fraction) = numerateur; \ Denom(fraction) = denominateur; \ } enum NomDesOperateurs { ADDITION=0 ,SOUSTRACTION ,MULTIPLICATION ,DIVISION ,EXPONENTIATION ,nOPERATEURS }; #define UNDEF \ 4444719 int FaireCommeSiTousLesOperateursEtaientNonCommutatifs=FAUX; int AccepterLesMultiplicationsParUn=VRAI; int AccepterLesDivisionsParUn=VRAI; int AccepterLesExponentiationsParUn=VRAI; int PouvoirUtiliserPlusieursFoisChaqueNombre=FAUX; /* Divers indicateurs de controle du fonctionnement de la fonction 'operation(...)'. */ int ListeOperators[nOPERATEURS]= { ADDITION, SOUSTRACTION, MULTIPLICATION, DIVISION, EXPONENTIATION }; int ListeUtilises[nOPERATEURS]= { VRAI, VRAI, VRAI, VRAI, FAUX }; int ListeCommutativites[nOPERATEURS]={ VRAI, FAUX, VRAI, FAUX, FAUX }; /* Liste des 'nOPERATEURS' operateurs autorises et utilisables 0, 1, 2,... fois. */ int ListeNombresEntiers[nNOMBRES]={N1,N2,N3,N4}; Fraction ListeNombres[nNOMBRES]; /* Liste des 'nNOMBRES' nombres autorises et obligatoires une seule fois... */ #define ri \ (INDEX0-UNDEF) Fraction operation(int xIndex,Fraction x,int IndexOperateur,Fraction y,int yIndex) /* Fonction calculant : */ /* */ /* x.operateur.y */ /* */ /* Les arguments '?Index' indiquent si le nombre correspondant ('x' ou 'y') est l'un */ /* des nombres de la liste 'ListeNombres' (auquel cas c'est index superieur ou egal a */ /* 'INDEX0') ou bien un resultat anterieur (auquel cas il est inferieur a 'INDEX0'). */ { Fraction resultat; EGAL(resultat,UNDEF,UNDEF); /* La valeur 'UNDEF' est choisie de facon a ce qu'une operation la donnant comme resultat */ /* soit eliminee de la recherche ulterieurement... */ if ( (ListeUtilises[IndexOperateur] == VRAI) && ( ( (Numer(x) != UNDEF) && (Denom(x) != UNDEF) && (Numer(y) != UNDEF) && (Denom(y) != UNDEF) ) ) && ( ( (Denom(x) != 0) && (Denom(y) != 0) ) ) && ( (FaireCommeSiTousLesOperateursEtaientNonCommutatifs == VRAI) || (ListeCommutativites[IndexOperateur] == FAUX) /* Cas ou l'operateur ne commute pas. */ || ( (ListeCommutativites[IndexOperateur] == VRAI) && ( (xIndex < INDEX0) || (yIndex < INDEX0) ) ) /* Cas ou l'operateur commute et porte sur deux nombres 'x' et 'y' dont l'un au moins des */ /* deux n'est pas elementaire. */ || ( (ListeCommutativites[IndexOperateur] == VRAI) && ( (xIndex >= INDEX0) && (yIndex >= INDEX0) && (xIndex < yIndex) ) ) /* Cas ou l'operateur commute et porte sur deux nombres 'x' et 'y' elementaires tel que */ /* l'index du premier est inferieur a celui du second ; le cas 'xIndex>yIndex' n'a donc */ /* pas a etre teste a cause donc de la commutativite. */ ) ) { switch (ListeOperators[IndexOperateur]) { case ADDITION: { EGAL(resultat ,(Numer(x)*Denom(y))+(Numer(y)*Denom(x)) ,(Denom(x)*Denom(y)) ); break; } case SOUSTRACTION: { EGAL(resultat ,(Numer(x)*Denom(y))-(Numer(y)*Denom(x)) ,(Denom(x)*Denom(y)) ); break; } case MULTIPLICATION: { if ( ( (Numer(x) != Denom(x)) && (Numer(y) != Denom(y)) ) || (AccepterLesMultiplicationsParUn == VRAI) ) { EGAL(resultat ,(Numer(x)*Numer(y)) ,(Denom(x)*Denom(y)) ); } else { /* La multiplication par 1 est indeterminee de facon a l'exclure de la recherche. */ } break; } case DIVISION: { if (Numer(y) != 0) { if ( (Numer(y) != Denom(y)) || (AccepterLesDivisionsParUn == VRAI) ) { EGAL(resultat ,(Numer(x)*Denom(y)) ,(Denom(x)*Numer(y)) ); } else { /* La division par 1 est indeterminee de facon a l'exclure de la recherche. */ } } else { /* La division par 0 est indeterminee de facon a l'exclure de la recherche. */ } break; } case EXPONENTIATION: { if ( ((Numer(x)*Denom(x)) > 0) && ((Numer(y)*Denom(y)) > 0) ) if ( (Numer(y) != Denom(y)) || (AccepterLesExponentiationsParUn == VRAI) ) { EGAL(resultat ,pow(Numer(x),Numer(y)/Denom(y)) ,pow(Denom(x),Numer(y)/Denom(y)) ); } else { /* L'exponentiation unitaire est indeterminee de facon a l'exclure de la recherche. */ } else { /* L'exponentiation negative ou nulle est indeterminee de facon a l'exclure de la recherche. */ } break; } default: { fprintf(stderr,"L'operateur '%d' n'est pas reconnu\n",ListeOperators[IndexOperateur]); } } } else { } return(resultat); } #define CONVERSION(operateur) \ COND(operateur == ADDITION \ ,"+" \ ,COND(operateur == SOUSTRACTION \ ,"-" \ ,COND(operateur == MULTIPLICATION \ ,"*" \ ,COND(operateur == DIVISION \ ,"/" \ ,COND(operateur == EXPONENTIATION \ ,"^" \ ,"?" \ ) \ ) \ ) \ ) \ ) #define FORMAT_s__ \ "%s" #define FORMAT_ds_ \ "%d%s" #define FORMAT_sd_ \ "%s%d" #define FORMAT_dsd \ "(%d%s%d)" #define EDITION(sequence) \ { \ arbre++; \ \ if ( (Numer(R3) == RESULTAT_ATTENDU) \ && (Denom(R3) == UNITE) \ ) \ { \ printf("arbre %d : ",arbre); \ sequence; \ printf(" = %d\n",Numer(R3)); \ } \ else \ { \ } \ } #define N1 \ ListeNombres[n1] #define N2 \ ListeNombres[n2] #define N3 \ ListeNombres[n3] #define N4 \ ListeNombres[n4] #define P1 \ Numer(N1) #define P2 \ Numer(N2) #define P3 \ Numer(N3) #define P4 \ Numer(N4) #define O1 \ CONVERSION(ListeOperators[o1]) #define O2 \ CONVERSION(ListeOperators[o2]) #define O3 \ CONVERSION(ListeOperators[o3]) main() { int n1,n2,n3,n4; /* Index des 'nNOMBRES' nombres. */ for (n1=INDEX0 ; n1<nNOMBRES ; n1++) { EGAL(N1,ListeNombresEntiers[n1],UNITE); /* Conversion des nombres entiers N en nombres rationnels N/1. */ } for (n1=INDEX0 ; n1<nNOMBRES ; n1++) { for (n2=INDEX0 ; n2<nNOMBRES ; n2++) { for (n3=INDEX0 ; n3<nNOMBRES ; n3++) { for (n4=INDEX0 ; n4<nNOMBRES ; n4++) { if ( (PouvoirUtiliserPlusieursFoisChaqueNombre == VRAI) || ( (P1 != P2) && (P1 != P3) && (P1 != P4) && (P2 != P3) && (P2 != P4) && (P3 != P4) ) ) /* Les 'nNOMBRES' nombres doivent etre tous utilises et ce une seule fois... */ { int o1,o2,o3; /* Index des 3 (=(nNOMBRES-1)) operateurs utiles (il en faut un de moins que de nombres...). */ for (o1=INDEX0 ; o1<nOPERATEURS ; o1++) { for (o2=INDEX0 ; o2<nOPERATEURS ; o2++) { for (o3=INDEX0 ; o3<nOPERATEURS ; o3++) { int arbre=0; /* Identification de l'arbre utilise (1,2,...). */ Fraction R1,R2,R3; R1=operation(n1,N1,o1,N2,n2); R2=operation(n3,N3,o3,N4,n4); R3=operation(ri,R1,o2,R2,ri); EDITION( { printf(FORMAT_dsd,P1,O1,P2); printf(FORMAT_s__,O2); printf(FORMAT_dsd,P3,O3,P4); } ); /* Test de l'arbre symetrique ("1") : */ /* */ /* n1 n2 n3 n4 */ /* \ / \ / */ /* \ / \ / */ /* o1 o3 */ /* (R1) (R2) */ /* \ / */ /* \ / */ /* \ / */ /* \ / */ /* o2 */ /* (R3) */ /* */ /* soit : */ /* */ /* arbre 1 : (n1.o1.n2).o2.(n3.o3.n4) */ /* */ R1=operation(n1,N1,o1,N2,n2); R2=operation(ri,R1,o2,N3,n3); R3=operation(ri,R2,o3,N4,n4); EDITION( { printf("("); printf(FORMAT_dsd,P1,O1,P2); printf(FORMAT_sd_,O2,P3); printf(")"); printf(FORMAT_sd_,O3,P4); } ); /* Test du premier arbre dissymetrique ("2") : */ /* */ /* n1 n2 */ /* \ / */ /* \ / */ /* o1 n3 */ /* (R1) / */ /* \ / */ /* o2 n4 */ /* (R2) / */ /* \ / */ /* o3 */ /* (R3) */ /* */ /* soit : */ /* */ /* arbre 2 : ((n1.o1.n2).o2.n3).o3.n4 */ /* */ R1=operation(n2,N2,o2,N3,n3); R2=operation(n1,N1,o1,R1,ri); R3=operation(ri,R2,o3,N4,n4); EDITION( { printf("("); printf(FORMAT_ds_,P1,O1); printf(FORMAT_dsd,P2,O2,P3); printf(")"); printf(FORMAT_sd_,O3,P4); } ); /* Test du second arbre dissymetrique ("3") : */ /* */ /* */ /* n2 n3 */ /* \ / */ /* \ / */ /* n1 o2 */ /* \ (R1) */ /* \ / */ /* o1 n4 */ /* (R2) / */ /* \ / */ /* o3 */ /* (R3) */ /* */ /* soit : */ /* */ /* arbre 3 : (n1.o1.(n2.o2.n3)).o3.n4 */ /* */ R1=operation(n3,N3,o3,N4,n4); R2=operation(n2,N2,o2,R1,ri); R3=operation(n1,N1,o1,R2,ri); EDITION( { printf(FORMAT_ds_,P1,O1); printf("("); printf(FORMAT_ds_,P2,O2); printf(FORMAT_dsd,P3,O3,P4); printf(")"); } ); /* Test du troisieme arbre dissymetrique ("4") : */ /* */ /* */ /* */ /* */ /* */ /* n3 n4 */ /* \ / */ /* \ / */ /* n2 o3 */ /* \ (R1) */ /* \ / */ /* n1 o2 */ /* \ (R2) */ /* \ / */ /* o1 */ /* (R3) */ /* */ /* soit : */ /* */ /* arbre 4 : n1.o1.(n2.o2.(n3.o3.n4)) */ /* */ R1=operation(n2,N2,o2,N3,n3); R2=operation(ri,R1,o3,N4,n4); R3=operation(n1,N1,o1,R2,ri); EDITION( { printf(FORMAT_ds_,P1,O1); printf("("); printf(FORMAT_dsd,P2,O2,P3); printf(FORMAT_sd_,O3,P4); printf(")"); } ); /* Test du quatrieme arbre dissymetrique ("5") : */ /* */ /* */ /* n2 n3 */ /* \ / */ /* \ / */ /* o2 n4 */ /* (R1) / */ /* \ / */ /* n1 o3 */ /* \ (R2) */ /* \ / */ /* o1 */ /* (R3) */ /* */ /* soit : */ /* */ /* arbre 5 : n1.o1.((n2.o2.n3).o3.n4) */ /* */ } } } } else { } } } } } }