9

私は競技会のためにいくつかの練習問題をやっていて、一日中このアルゴリズムに取り組んでいます。問題全体を読みたい方はこちらですが、ちょっと長い問題なので簡単に説明します。

問題:

ID 番号をチェックサムに差し込んで ID 番号を確認する必要があります。ID をアルゴリズムに組み込む前に、ID を base-10 に変換する必要があります。ID 番号は文字で始まります。

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

これらの文字から base-10 への変換に問題はありません。私の変換コードは適切なので、問題の次の部分を示します。

パート2:

ベース 10 の ID 番号を取得したら、それを次のアルゴリズムにプラグインする必要があります。

注: 各 ID 番号は 8 桁の長さでなければなりません。8 桁以上の番号の前には 0 が付きます。

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

簡単にするために:

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

ここで最も重要なことは、X が演算 * (乗算) ではないということです。X は後で定義される独自の操作です。

注: 最上位桁のように見えますd7が、よくわかりません。問題はあまり明確ではありません。


f(n1, n2)、g(n)、および演算子 X の定義は次のとおりです。

f(n1, n2) =

f(n1,n2)

g(n) =

おやすみなさい)

オペレーター X:

オペレーターX

私のコードmodと同じだと思いましたが、慣れていない別の操作があるかどうかはわかりませんでした。%mod

私の構造

これが私が問題を解決したいと決めた方法です:

  1. 基数 10 の数値を次のように変換します。int[8]
  2. int[8]スルーの各桁を入れるf(n, dn)
  3. X 演算子を使用して、それらをすべて結合します。

マイコード

これが私のアルゴリズム関数です。どこかで混乱している場合はコメントできますが、実際には上記のアルゴリズムに正確に従っています。

/*
 * This will return the checksum of the id.
 * Formula: F(0, d0) X F(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 && num2 >= 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};

さて、ここに私のmain(String args[])コードがあります:

注: 機能を想定でき、parseBase10適切toArrayに機能しています。問題の入出力例で確認しました。

public static void main(String 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

            String[] list = new String[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;
    }
}

自分でコンパイルしたいですか?

ここに私の完全な(未編集の)コードがあります:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;

public class Main 
{
    public static void main(String 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

                String[] list = new String[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) X F(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 && num2 >= 5)
            return (num1 + (num2 - 5)) % 5 + 5;
        if(num1 >= 5 && num2 < 5)
            return ((num1 - 5) - num2) % 5 + 5;
        return (num1 - num2) % 5;
    }

    /*
     * This will convert a number to an array equivalent of that number
     * The result will be 8 digites long with leading 0's if possible.
     * 
     * EX:
     * 12345 = {0, 0, 1, 2, 3, 4, 5, 6}
     */
    public static int[] toArray(int value)
    {
        int result[] = new int[8];

        for(int x = result.length - 1;x >= 0;x--)
        {
            result[x] = value % 10;
            value /= 10;
        }

        return result;
    }

    /*
     * converts a String 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(String string) throws Exception
    {
        int multiplier = 1;
        int result = 0; // in base 10

        for(int x = string.length() - 1;x >= 0;x--)
        {
            char letter = string.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};
}

これが私が私の問題に与えている入力です:

6
WYYXWVZXX
YWYWYYXWVZYY
YWYWYYXWVZYX
YYZWYYXWVZYX
YXXWYYXWVZXW
XYZWYYXWXYY

ここに私が得るものがあります:

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*

が表示されている*0*場所は、0 を取得するはずの場所ですが、別の値を取得しています。私のチェックサムアルゴリズムはどこでめちゃくちゃになっていますか?

これらすべてを読んで、私のコードのどの部分についても自由に説明を求めてください。

4

2 に答える 2

7

バグ 1

エラーは微妙です。まず、問題の数字の説明は次のとおりd7 d6 ... d1 d0 です。つまり、d0は 10 進数の単位値です。

次に、彼らは F が連想のままであると言い、そのプロセスを次のように説明します。

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

つまり、最初Fにオペレーターに適用する必要がありますd0。しかし、int 配列を作成すると、インデックス 0 の要素はd7になります。この場合、順序が重要であるため、間違った結果が得られます。

解決するには、10 進数値の int 配列表現を逆にするだけです。

バグ 2

2 番目の間違いは、モジュロ 5 の演算にあります。問題のメモにあるように、次のように書かれています。

-4 mod 5 = 1 であることに注意してください。

したがって、演算子をコピーして貼り付けるxのは間違いです。次のように変更します。

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;
}

期待される結果が得られます。

両方のバグが修正された結果は次のとおりです。

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

編集

BUG 2 のより一般的な解決策については、Martijn Courteaux の回答を確認してください。

于 2013-09-07T22:47:57.087 に答える
3

あなたのmod論理は壊れています。ウェブサイトには次のように書かれています。

注意してください-4 % 5 = 1

Java では、これは当てはまりません: (-4) % 5 == -4. したがって、独自の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;
}

または@ durron597によって提案されたよりパフォーマンスの高い実装:

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

ここでは負の値を使用するため、これは非常に重要です(例:と
仮定):num1 = 5num2 = 4

if(num1 >= 5 && num2 < 5)
    return ((num1 - 5) - num2) % 5 + 5;
于 2013-09-07T23:19:40.310 に答える