如何更好地解决这个问题

时间:2014-07-27 17:03:17

标签: java algorithm recursion dynamic-programming

以下问题来自最近的编程竞赛。

GCD游戏

生与死,无论输赢,都有两面性。这就是Arjit和Chandu Don所争论的。他们厌倦了彼此之间的团结战争,因此决定像数学领域的男人一样定居 但即使在玩数学游戏时,他们还没有放弃相互伤害的策略。所以,Arjit带着一些自己的橡皮子弹,而Chandu Don带着b个橡皮子弹。因为,Little Chandu是两个中更危险的黑帮,他决定给Arjit第一次机会。
他们决定谁赢得整个HEpur土地的方式是玩古老的GCD-DCG游戏。第一个最终只有一颗子弹将会输掉。 这就是游戏的进展:

1. If GCD (a, b) is greater than 1, then, the player can: 
    a.) Subtract 1 from opposite player’s bullets. **OR** 
    b.) Divide the number of bullets of opposite player by GCD (a, b). 
2. If GCD (a, b) is equal to 1, then, the player can: 
    a.) Subtract 1 from the opposite player’s bullets.

Note : Player can choose only one move out of two if GCD(A,B) > 1 .

The one who ends up with only one bullet loses the battle, 
and his life, and the land of HEpur.

一劳永逸地确定谁将统治!

输入:
第一行包含测试用例T的数量,接下来的T行包含分别由Arjit和Chandu Don拍摄的两个数字A和B.

输出:
在平局打印Draw的情况下打印游戏的赢家名称。 约束

1 <= T <= 1000
1 <= A <= 1000
1 <= B <= 1000

问题陈述信用:Arjit Srivastava。

Sample Input
4
2 1
3 4
5 5
1 1
Sample Output
Arjit
Chandu Don
Arjit
Draw

我在这里添加我的解决方案:

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

public class TestClass 
{
    public static void main(String args[] ) throws Exception 
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int noOfTestCases = Integer.parseInt( br.readLine() );

        for( int inx = 0; inx < noOfTestCases; ++inx )
        {
            StringTokenizer st = new StringTokenizer( br.readLine() );

            int a = 0;
            int b = 0;

            while( st.hasMoreTokens())
            {
                a = Integer.parseInt( st.nextToken() );
                b = Integer.parseInt( st.nextToken() );                     
            }

            doStuff( a, b, true);
        }
    }

    private static boolean doStuff(int a, int b, boolean arjitInPlay ) 
    {
        if( a == 1 && b == 1 )
        {
            System.out.println( "Draw" );
            return true;
        }

        if( a == 1 )
        {
            System.out.println( "Chandu Don" );
            return true;
        }

        if( b == 1 )
        {
            System.out.println( "Arjit" );
            return true;
        }

        int result = getGCD( a, b );


        if( arjitInPlay )
        {
            if( result > 1 )
            {
                return doStuff( a, b - 1, !arjitInPlay ) || doStuff( a, b / result, !arjitInPlay );
            }
            else if ( result == 1 )
            {
                return doStuff( a, b - 1, !arjitInPlay );
            }
        }
        else
        {
            if( result > 1 )
            {
                return doStuff( a - 1, b, !arjitInPlay ) || doStuff( a / result, b, !arjitInPlay );
            }
            else if ( result == 1 )
            {
                return doStuff( a - 1, b, !arjitInPlay );
            }               
        }
        return false;
    }

    private static int getGCD(int a, int b) 
    {
        if (b == 0)
        {
            return a;
        }
        return getGCD(b, a % b);
    }
}

我在这里有两个问题:

  • 递归是可以在这里使用的最佳数据结构吗?或者这是否需要另一个数据结构或算法类。
  • 有一个称为修剪权的概念......在确定它们不会产生良好结果后,很少有路径被切断。有人可以帮我修改上面的代码[更好,而不是短路]。
  • 这段代码有什么问题? 3次测试中有1次正在通过。其他两个都失败了。

感谢, 帕。

1 个答案:

答案 0 :(得分:0)

我还没有尝试在任何自动判断系统上解决问题,但我有以下建议:

假设他们发挥得最好。

根据约束,使用递归是完全正确的,但是你的实现有一个bug。你的代码所做的只是每个回合,每个用户从相反的中移除1个子弹,我认为你的短路中的第二个函数调用没有被执行。换句话说,您的代码将声明拥有更多项目符号的人作为获胜者。您可以尝试8 5作为输入。你的代码输出'Arjit',但实际上它应该是'Chandu Don'。

恕我直言,解决问题的最佳方法是使用3D数组win[i][j][k],而不是像DFS一样完成计算方法,而不是像DFS那样,表示玩家{{1}当玩家0拥有k个子弹而玩家1拥有i个子弹时,他将会获胜。请注意,绘制游戏只能在输入为j时发生。

以玩家0为例,1 1win[i][j][0]当且仅当Truewin[i][j - 1][1]False时(如果win[i][j / gcd(i, j)][1] )是gcd(i, j) > 1。玩家1的计算方法类似。

我知道这与您的想法基本相同,但通过这样做,可以为所有False缓存计算结果,因此将来的查询/访问将非常快。