Quel est le problème avec mon algorithme de sum de contrôle?

Je fais quelques problèmes de pratique pour une compétition et je travaille sur cet algorithme comme toute la journée. Si vous voulez lire le problème dans son ensemble, je vais vous donner une brève explication car c’est un problème assez long.

Problème:

Vous devez vérifier les numéros d’identité en les connectant à une sum de contrôle. L’ID doit être converti en base 10 avant que vous puissiez le connecter à l’algorithme. Le numéro d’identification commence par les lettres:

Z = 0, Y = 1, X = 2, W = 3, V = 4

Je n’ai pas de problème avec la conversion de ces lettres en base 10, mon code de conversion est bon, je vais donc vous montrer la partie suivante du problème:

Partie 2:

Une fois que vous avez votre numéro d’identification base 10, vous devez le connecter à l’algorithme suivant:

Remarque: chaque numéro d’identification DOIT comporter 8 chiffres, le chiffre 0 précédant un numéro qui ne soit pas au moins 8 chiffres.

checksum = F(0, d0) XF(1, d1) XF(2, d2) ... 

Donc pour simplifier:

 checksum = F(n, dn) XF(n+1, dn) ... where n is the index of the digit 

Le plus important ici est que X n’est pas l’opération * (multiplier). X est sa propre opération définie plus tard.

Remarque: le chiffre le plus significatif semble être d7 mais je ne suis pas sûr, le problème n’est pas très clair.


Voici les définitions de f (n1, n2), g (n) et de l’opérateur X:

f (n1, n2) =

f (n1, n2)

g (n) =

g (n)

opérateur X:

Opérateur X

J’ai supposé que mod était la même chose que % dans mon code, je n’étais pas sûr s’il y avait une autre opération de mod que je ne connaissais pas.

Ma structure

Voici comment j’ai décidé de résoudre le problème:

  1. Convertir le nombre base-10 en int[8]
  2. Placez chaque chiffre de l’ int[8] à f(n, dn)
  3. Utilisez l’opérateur X pour les combiner tous ensemble.

Mon code

Voici mes fonctions d’algorithme. Je peux les commenter s’ils confondent quelque part, mais ils suivent vraiment l’algorithme indiqué plus haut.

 /* * This will return the checksum of the id. * Formula: F(0, d0) XF(1, d1) ... * * F(n, dn) where n is the current index. * X != * (multiply)!! X is a defined operator */ public static int getChecksum(int[] id) { int result = 0; for(int x = 0;x < id.length;x++) { if(x == 0) result = fOfxd(x, id[x]); else{ result = opX(result, fOfxd(x, id[x])); } } return result; } public static int gOfx(int x) { return GOFX[x]; } public static int fOfxd(int x, int d) { switch(x) { case 0: return d; case 1: return gOfx(d); default: return fOfxd(x - 1, gOfx(d)); } } public static int opX(int num1, int num2) { if(num1 < 5 && num2 < 5) return (num1 + num2) % 5; if(num1 = 5) return (num1 + (num2 - 5)) % 5 + 5; if(num1 >= 5 && num2 < 5) return ((num1 - 5) - num2) % 5 + 5; return (num1 - num2) % 5; } public static final int[] GOFX = {1, 5, 7, 6, 2, 8, 3, 0, 9, 4}; 

Maintenant, voici mon code main(Ssortingng args[]) :

Remarque: Vous pouvez supposer que les fonctions parseBase10 et toArray fonctionnent correctement. Je les ai vérifiées avec les exemples d’entrée / sortie du problème.

 public static void main(Ssortingng args[]) { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); while(true) { int ids = 0; // how many ids are we checking? try { ids = Integer.parseInt(reader.readLine()); // get user input Ssortingng[] list = new Ssortingng[ids]; // will hold all of the ids for(int x = 0;x < list.length;x++) list[x] = reader.readLine(); // reads all of the ids we will be checking for(int x = 0;x < list.length;x++) // lets check the ids individually now { String stringID = list[x]; // the string representation of the id int base10 = parseBase10(stringID); int[] id = toArray(base10); int checksum = getChecksum(id); System.out.println(stringID); System.out.println(base10); System.out.println(Arrays.toString(id)); System.out.println(checksum); } }catch(Exception e){e.printStackTrace();} break; } } 

Voulez-vous le comstackr vous-même?

Voici mon code complet (non édité):

 import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Arrays; public class Main { public static void main(Ssortingng args[]) { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); while(true) { int ids = 0; // how many ids are we checking? try { ids = Integer.parseInt(reader.readLine()); // get user input Ssortingng[] list = new Ssortingng[ids]; // will hold all of the ids for(int x = 0;x < list.length;x++) list[x] = reader.readLine(); // reads all of the ids we will be checking for(int x = 0;x < list.length;x++) // lets check the ids individually now { String stringID = list[x]; // the string representation of the id int base10 = parseBase10(stringID); int[] id = toArray(base10); int checksum = getChecksum(id); System.out.println(stringID); System.out.println(base10); System.out.println(Arrays.toString(id)); System.out.println(checksum); } }catch(Exception e){e.printStackTrace();} break; } } /* * This will return the checksum of the id. * Formula: F(0, d0) XF(1, d1) ... * * F(n, dn) where n is the current index. * X != * (multiply)!! X is a defined operator */ public static int getChecksum(int[] id) { int result = 0; for(int x = 0;x < id.length;x++) { if(x == 0) result = fOfxd(x, id[x]); else{ result = opX(result, fOfxd(x, id[x])); } } return result; } public static int gOfx(int x) { return GOFX[x]; } public static int fOfxd(int x, int d) { switch(x) { case 0: return d; case 1: return gOfx(d); default: return fOfxd(x - 1, gOfx(d)); } } public static int opX(int num1, int num2) { if(num1 < 5 && num2 < 5) return (num1 + num2) % 5; if(num1 = 5) return (num1 + (num2 - 5)) % 5 + 5; if(num1 >= 5 && num2 = 0;x--) { result[x] = value % 10; value /= 10; } return result; } /* * converts a Ssortingng sequence and converts it to a base 10 equivalent. * Z = 0, Y = 1, X = 2, W = 3, V = 4 * * EX: * YY = 11(base-5) = 6(base-10) */ public static int parseBase10(Ssortingng ssortingng) throws Exception { int multiplier = 1; int result = 0; // in base 10 for(int x = ssortingng.length() - 1;x >= 0;x--) { char letter = ssortingng.charAt(x); // the letter we are parsing int value = -1; // initial value, set to -1 to check for parsing error for(int y = 0;y < VALUES.length;y++) if(letter == VALUES[y]) value = y; // letter found in VALUES[] if(value == -1) throw new Exception("Could not parse: " + letter); // the specified letter was not found result += (multiplier * value); /* ^^ this moves the value to the correct digit place by using a multiplier: * EX: * * current result: 45 (base-10) * new value to parse: 2 (base-5) * 45(base-10) + (2(base-5) * 25(base-10)) = 245 <-- correct output */ multiplier *= 5; // sets up multiplier for next value } return result; } public static final char[] VALUES = {'Z', 'Y', 'X', 'W', 'V'}; public static final int[] GOFX = {1, 5, 7, 6, 2, 8, 3, 0, 9, 4}; } 

Voici l’entrée que je donne mon problème:

6
WYYXWVZXX
YWYWYYXWVZYY
YWYWYYXWVZYX
YYZWYYXWVZYX
YXXWYYXWVZXW
XYXWYYXWXYY

Voici ce que je reçois:

 WYYXWVZXX 1274262 [0, 1, 2, 7, 4, 2, 6, 2] 2 *0* YWYWYYXWVZYY 81352381 [8, 1, 3, 5, 2, 3, 8, 1] 0 YWYWYYXWVZYX 81352382 [8, 1, 3, 5, 2, 3, 8, 2] 4 YYZWYYXWVZYX 59868007 [5, 9, 8, 6, 8, 0, 0, 7] 0 YXXWYYXWVZXW 73539888 [7, 3, 5, 3, 9, 8, 8, 8] 5 *0* XYXWYYXWXYY 22520431 [2, 2, 5, 2, 0, 4, 3, 1] 3 *0* 

Là où vous voyez les *0* , c’est là où je suis censé avoir 0, mais j’obtiens une valeur différente. Où se trouve mon algorithme de sum de contrôle?

En lisant tout cela, n’hésitez pas à demander des éclaircissements sur une partie de mon code.

BUG 1

L’erreur est subtile. Tout d’abord, la description du chiffre dans le problème est la suivante: d7 d6 ... d1 d0 cela signifie que d0 est la valeur unitaire du nombre décimal.

Ensuite, ils disent que F rest associatif et décrivent le processus comme suit:

 F(0,d0) x F(1,d1) x F(2,d2) x ... x F(6,d6) x F(7,d7) 

cela signifie que vous devez d’abord appliquer F à l’opérateur pour d0 . MAIS lorsque vous créez le tableau int, l’élément à l’index 0 est d7 , et puisque dans ce cas, l’ordre est important, vous obtenez un résultat erroné.

Pour résoudre ce problème, il vous suffit d’inverser la représentation décimale de votre tableau int.

BUG 2

La deuxième erreur est dans l’opération modulo 5. Comme vous pouvez le lire dans la note du problème, ils disent:

Notez que -4 mod 5 = 1.

Copier-coller de l’opérateur x est donc une erreur. Changez-le avec:

 public static int opX(int num1, int num2) { if(num1 < 5 && num2 < 5) return (num1 + num2) % 5; if(num1 < 5 && num2 >= 5) return (num1 + (num2 - 5)+5) % 5 + 5; if(num1 >= 5 && num2 < 5) return ((num1 - 5) - num2+20) % 5 + 5; return (num1 - num2 +10) % 5; } 

et vous obtiendrez le résultat attendu.

Voici le résultat avec les deux bugs corrigés:

 1274262 [2, 6, 2, 4, 7, 2, 1, 0] 0 YWYWYYXWVZYY 81352381 [1, 8, 3, 2, 5, 3, 1, 8] 0 YWYWYYXWVZYX 81352382 [2, 8, 3, 2, 5, 3, 1, 8] 1 YYZWYYXWVZYX 59868007 [7, 0, 0, 8, 6, 8, 9, 5] 0 YXXWYYXWVZXW 73539888 [8, 8, 8, 9, 3, 5, 3, 7] 0 XYXWYYXWXYY 22520431 [1, 3, 4, 0, 2, 5, 2, 2] 0 

MODIFIER

Pour une solution plus générale du BUG 2, vérifiez la réponse de Martijn Courteaux.

Votre logique de mod est cassée. Le site Web dit:

Notez que -4 % 5 = 1 .

En Java, ce n’est pas vrai: (-4) % 5 == -4 . Alors implémentez votre propre méthode mod(int a, int b) :

 public static int mod(int a, int b) { while (a < 0) a += b; while (a >= b) a -= b; return a; } 

Ou une implémentation plus performante suggérée par @ durron597 :

 public static int mod(int a, int b) { a %= b; return a < 0 ? a + b : a; } 

Ceci est vraiment important puisque vous aurez des valeurs négatives ici
(Par exemple, supposons num1 = 5 et num2 = 4 ):

 if(num1 >= 5 && num2 < 5) return ((num1 - 5) - num2) % 5 + 5;