3

I'm solving Uva's 3n+1 problem and I don't get why the judge is rejecting my answer. The time limit hasn't been exceeded and the all test cases I've tried have run correctly so far.

   import java.io.*;



public class NewClass{

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException {

        int maxCounter= 0; 
        int input; 

        int lowerBound; 
        int upperBound; 
        int counter;
        int numberOfCycles;
        int maxCycles= 0;
        int lowerInt;
        BufferedReader consoleInput = new BufferedReader(new InputStreamReader(System.in));
        String line = consoleInput.readLine();
        String [] splitted =  line.split(" ");

        lowerBound = Integer.parseInt(splitted[0]);
        upperBound = Integer.parseInt(splitted[1]);


        int [] recentlyused =  new int[1000001];



if (lowerBound > upperBound )
{
    int h = upperBound;
    upperBound = lowerBound;
    lowerBound = h;

}
lowerInt = lowerBound;
        while (lowerBound <= upperBound)
        {
            counter = lowerBound;
            numberOfCycles = 0;


            if (recentlyused[counter] == 0)
            {
                while ( counter != 1 )
                {


                        if (recentlyused[counter] != 0)
                        {

                        numberOfCycles = recentlyused[counter] + numberOfCycles;
                        counter = 1;
                        }
                        else
                        {
                            if (counter % 2 == 0)
                            {
                            counter = counter /2;
                            }
                            else
                            {
                            counter = 3*counter + 1;
                            }
                            numberOfCycles++;
                        }

                }
            }
            else
            {

            numberOfCycles = recentlyused[counter] + numberOfCycles;
            counter = 1;
            }

            recentlyused[lowerBound] = numberOfCycles;



            if (numberOfCycles > maxCycles)
            {
            maxCycles = numberOfCycles;
            }

            lowerBound++;
        }
        System.out.println(lowerInt +" "+ upperBound+ " "+ (maxCycles+1));

    }


}
animuson
  • 53,861
  • 28
  • 137
  • 147
andandandand
  • 21,946
  • 60
  • 170
  • 271

8 Answers8

2

Are you making sure to accept the entire input? It looks like your program terminates after reading only one line, and then processing one line. You need to be able to accept the entire sample input at once.

AlbertoPL
  • 11,479
  • 5
  • 49
  • 73
1

I faced the same problem. The following changes worked for me:

  • Changed the class name to Main.
  • Removed the public modifier from the class name.

The following code gave a compilation error:

public class Optimal_Parking_11364 {
    public static void main(String[] args) {
        ...
    }
}

Whereas after the changes, the following code was accepted:

class Main {
    public static void main(String[] args) {
        ...
    }
}

This was a very very simple program. Hopefully, the same trick will also work for more complex programs.

rhitz
  • 1,892
  • 2
  • 21
  • 26
sudhir shakya
  • 827
  • 1
  • 9
  • 21
0

If I understand correctly you are using a memoizing approach. You create a table where you store full results for all the elements you have already calculated so that you do not need to re-calculate results that you already know (calculated before).

The approach itself is not wrong, but there are a couple of things you must take into account. First, the input consists of a list of pairs, you are only processing the first pair. Then, you must take care of your memoizing table limits. You are assuming that all numbers you will hit fall in the range [1...1000001), but that is not true. For the input number 999999 (first odd number below the upper limit) the first operation will turn it into 3*n+1, which is way beyond the upper limit of the memoization table.

Some other things you may want to consider are halving the memoization table and only memorize odd numbers, since you can implement the divide by two operation almost free with bit operations (and checking for even-ness is also just one bit operation).

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • I noticed that as well, there is potentially a lot of wasted table space. – AlbertoPL Jul 19 '09 at 22:39
  • well, the page on algorithmist says: To get the problem in good time you must create an array with size 1000000 then using recursion with memoization trying to not computing any value more than one will be good for 0.200 sec – andandandand Jul 20 '09 at 00:28
  • Yes of course, but say the range is from 100 - 200, you start storing those values at array index 100, which isnt the best. Also, it's possible your solution isn't fast enough, because when you hit certain values of counter, you're not remember recently hit values of counter, thus wasting time. When the counter is the same number as it was in a previous loop, you should know the answer at that point. – AlbertoPL Jul 20 '09 at 02:42
  • I am not discussing the general solution, but rather your implementation of it. You are not being careful on the indices you pass to the memorization array (if the input is big enough: 10^6 - 1) you will hit positions beyond the end of the array triggering an ArrayOutOfBounds (I think that is the name, did not code Java for long) exception and the code will break. Also note that you are not really doing what the proposed algorithm states: you only memorize the elements in the input range. This means that you will repeat calculations. – David Rodríguez - dribeas Jul 20 '09 at 05:16
  • Say the range is [2,7], first you calculate the sequence for 2, that starts with [2, 7 (which is 3*2 + 1) ... ], the value for 7 is not being cached in the results array, when you later hit the 7 you will recalculate it. That is the reason while the suggested algorithm uses recursion, as it is the easiest way of remembering the solutions to all intermediate results. – David Rodríguez - dribeas Jul 20 '09 at 05:18
  • So there are at least 2 things you must do to get your code up and running: beware of array limits and memorize _all_ intermediate results. – David Rodríguez - dribeas Jul 20 '09 at 05:19
  • Two comments above, the example numbers are wrong, it should not be [2,7], but rather [3, 10]. Once the numbers are corrected, the rest of the comment stands true. – David Rodríguez - dribeas Jul 20 '09 at 05:20
0

If possible Please use this Java specification : to read input lines http://online-judge.uva.es/problemset/data/p100.java.html

I think the most important thing in UVA judge is 1) Get the output Exactly same , No Extra Lines at the end or anywhere . 2) I am assuming , Never throw exception just return or break with No output for Outside boundary parameters. 3)Output is case sensitive 4)Output Parameters should Maintain Space as shown in problem

One possible solution based on above patterns is here https://gist.github.com/4676999


    /*

    Problem URL: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=36


    Home>Online Judge > submission Specifications 
    Sample code to read input is from : http://online-judge.uva.es/problemset/data/p100.java.html

    Runtime : 1.068
    */
    import java.io.*;
    import java.util.*;

    class Main
    {
        static String ReadLn (int maxLg)  // utility function to read from stdin
        {
            byte lin[] = new byte [maxLg];
            int lg = 0, car = -1;
            String line = "";

            try
            {
                while (lg < maxLg)
                {
                    car = System.in.read();
                    if ((car < 0) || (car == '\n')) break;
                    lin [lg++] += car;
                }
            }
            catch (IOException e)
            {
                return (null);
            }

            if ((car < 0) && (lg == 0)) return (null);  // eof
            return (new String (lin, 0, lg));
        }

        public static void main (String args[])  // entry point from OS
        {
            Main myWork = new Main();  // create a dinamic instance
            myWork.Begin();            // the true entry point
        }

        void Begin()
        {

            String input;
            StringTokenizer idata;
            int a, b,max;


            while ((input = Main.ReadLn (255)) != null)
            {
              idata = new StringTokenizer (input);
              a = Integer.parseInt (idata.nextToken());
              b = Integer.parseInt (idata.nextToken());

              if (a<b){
                  max=work(a,b);

              }else{
                  max=work(b,a);
              }
              System.out.println (a + " " + b + " " +max);
            }
        }

        int work( int a , int b){
            int max=0;
            for ( int i=a;i<=b;i++){
                int temp=process(i);
                if (temp>max) max=temp;
            }
            return max;
        }
        int process (long n){
            int count=1;
            while(n!=1){
                count++;
                if (n%2==1){
                    n=n*3+1;
                }else{
                    n=n>>1;
                }
            }

            return count;
        }
    }
aked
  • 5,625
  • 2
  • 28
  • 33
  • This a magic, but i have same alghorith and system don't accepted me until i change incoming parameter from `int` to `long`. You can explain me,why? –  Oct 19 '13 at 11:52
  • I submitted the code submission id [12526980] it did work. can i see your code ? – aked Oct 19 '13 at 16:33
0

Please consider that the integers i and j must appear in the output in the same order in which they appeared in the input, so for:

10 1

You should print

10 1 20
Walter R
  • 523
  • 1
  • 7
  • 10
0
package pandarium.java.preparing2topcoder;/*
 * Main.java
 *  java program model for www.programming-challenges.com
 */

import java.io.*;
import java.util.*;

class Main implements Runnable{
    static String ReadLn(int maxLg){  // utility function to read from stdin,
        // Provided by Programming-challenges, edit for style only
        byte lin[] = new byte [maxLg];
        int lg = 0, car = -1;
        String line = "";

        try
        {
            while (lg < maxLg)
            {
                car = System.in.read();
                if ((car < 0) || (car == '\n')) break;
                lin [lg++] += car;
            }
        }
        catch (IOException e)
        {
            return (null);
        }

        if ((car < 0) && (lg == 0)) return (null);  // eof
        return (new String (lin, 0, lg));
    }

    public static void main(String args[])  // entry point from OS
    {
        Main myWork = new Main();  // Construct the bootloader
        myWork.run();            // execute
    }

    public void run() {
        new myStuff().run();
    }
}
class myStuff implements Runnable{
    private String input;
    private StringTokenizer idata;
    private List<Integer> maxes;

    public void run(){

        String input;
        StringTokenizer idata;
        int a, b,max=Integer.MIN_VALUE;


        while ((input = Main.ReadLn (255)) != null)
        {
            max=Integer.MIN_VALUE;
            maxes=new ArrayList<Integer>();
            idata = new StringTokenizer (input);
            a = Integer.parseInt (idata.nextToken());
            b = Integer.parseInt (idata.nextToken());

            System.out.println(a + " " + b + " "+max);

        }
    }
    private static int getCyclesCount(long counter){
        int cyclesCount=0;
        while (counter!=1)
        {
            if(counter%2==0)
                counter=counter>>1;
            else
                counter=counter*3+1;
            cyclesCount++;
        }
        cyclesCount++;
        return cyclesCount;
    }
    // You can insert more classes here if you want.
}
0

This solution gets accepted within 0.5s. I had to remove the package modifier.

   import java.util.*;

    public class Main {

    static Map<Integer, Integer> map = new HashMap<>();

    private static int f(int N) {
        if (N == 1) {
            return 1;
        }

        if (map.containsKey(N)) {
            return map.get(N);
        }

        if (N % 2 == 0) {
            N >>= 1;
            map.put(N, f(N));
            return 1 + map.get(N);
        } else {
            N = 3*N + 1;
            map.put(N, f(N) );
            return 1 + map.get(N);
        }
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        try {
            while(scanner.hasNextLine()) {
                int i = scanner.nextInt();
                int j = scanner.nextInt();

                int maxx = 0;
                if (i <= j) {
                    for(int m = i; m <= j; m++) {
                        maxx = Math.max(Main.f(m), maxx);
                    }
                } else {
                    for(int m = j; m <= i; m++) {
                        maxx = Math.max(Main.f(m), maxx);
                    }
                }
                System.out.println(i + " " + j + " " + maxx);
            }
            System.exit(0);
        } catch (Exception e) {

        }


    }
}
H.Rabiee
  • 4,747
  • 3
  • 23
  • 35
0

Did you make sure that the output was in the same order specified in the input. I see where you are swapping the input if the first input was higher than the second, but you also need to make sure that you don't alter the order it appears in the input when you print the results out.

ex.

Input

10 1

Output

10 1 20

Sophy Pal
  • 435
  • 2
  • 7