简体   繁体   中英

how to decide logic for this algorithm

Can't figure out this problem for a long time.Help. Thanks

You are in a food logistics business. You have N jugs, each with unlimited capacity. Initially, each jug contains exactly 1 liter of juice. You want to carry these jugs to a delivery location, but you can only carry K jugs at a time. You don't want to waste any juice and you don't want to make more than one trip, so you decide to redistribute the contents of the jugs until you end up with no more than K non-empty jugs.

You are only allowed to redistribute the juice using the following method. First, pick two jugs that contain an equal amount of juice. Then, pour the entire content of one of those jugs into the other. Repeat this process as many times as necessary.

Because of this restriction, it may be impossible to end up with no more than K non-empty jugs using only the N jugs that you have initially. Fortunately, you can also buy more jugs. Each jug that you buy will contain exactly 1 liter of juice and have unlimited capacity. For example, consider the case where N is 3 and K is 1. It's impossible to get from 3 jugs to 1. If you pour one jug into another, you end up with one 2 liter jug and one 1 liter jug. At that point, you're stuck. However, if you then buy another jug, you can pour that jug into the 1 liter jug, and pour the resulting 2 liter jug into the other 2 liter jug to end up with just one 4 liter jug.

Return the minimum number of additional jugs you must buy in order to achieve your goal. If it's impossible, return -1 instead.

Constraints

– N will be between 1 and 10^7, inclusive.

– K will be between 1 and 1000, inclusive. Examples 1) Input 3 1 Output 1 (The example from the problem statement.) 2) Input 13 2 Output 3 (If you have 13, 14, or 15 jugs, you can't end up with one or two jugs. With 16 jugs, you can end up with one jug.) 3) Input 1000000 5 Output 15808

Observation: If T is the total number of 1 liter jugs you have (N plus the additional ones), then the number of bits in T's binary representation is the number of jugs to carry.

So the task is to find the next higher number up from (and including) N with at most K bits in its binary representation.

If N is limited upto 10^7, then even a simple brute-force search upward from N will do the job within a second or so.

Of course, there's lots of room for optimization then allowing for much higher N values...

The below code will produce the required result. All I've done here is adding the adjacent elements that are "equal" into a new ArrayList and the elements that "doesn't match" with it's adjacent element will be added as it is into the same 'ArrayList'. This new ArrayList generated is then passed as a parameter recursively into the function getExtJugs . This function sets the extra variable to the value of number of jugs to be added to get the result. As the extra variable is static it's value retains and So, it can be called through the main() function to output the result.

import java.util.*;

public class JugsTravel {

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    int m = in.nextInt();
    int k = in.nextInt();
    ArrayList<Integer> cap = new ArrayList<Integer>();
    for(int i=0; i<m; i++){
        cap.add(1);
    }

    getExtJugs(k, cap);
    System.out.println(extra);
}

static int extra = 0;

static void getExtJugs(int k, ArrayList<Integer> cap){
    if(cap.size() <= k){
        return ;
    }

    ArrayList<Integer> res = new ArrayList<Integer>();

    for(int i=0; i<cap.size(); i+=2){
        try{
            if(cap.get(i).intValue() == cap.get(i+1).intValue()){
                res.add(cap.get(i) + cap.get(i+1));
            }
            else if(cap.get(i).intValue() != cap.get(i+1).intValue()){
                res.add(cap.get(i));
                res.add(cap.get(i+1));
            }
        }catch(Exception e){
            res.add(cap.get(i));
        }
    }

    if(cap.size() == res.size()){
        extra = extra + Math.abs(res.get(res.size()-1) - res.get(res.size()-2));
        res.set(res.size()-1, res.get(res.size()-1) + extra);
        res.set(res.size()-2, res.get(res.size()-1)+res.get(res.size()-2));
        res.remove(res.size()-1);
        int c = res.size()-1;
        while(res.size()>0){
            try{
                if(res.get(c) == res.get(c-1)){
                    res.set(c-1, res.get(c) + res.get(c-1));
                    res.remove(res.size()-1);
                }
            }catch(Exception e){
                break;
            }
            c--;
        }
        getExtJugs(k, res);
    }else
        getExtJugs(k, res);
}

}

Hope, this helps!

Here's an optimised solution. It's using the binary representation of the number to find the number of jugs needed (as others mentioned). To compute the cost it uses the fact that the cost to change a 1 to a 0 increases exponentially as you go forward in the binary representation, so it's always cheaper to change 1's to 0's as soon as you find them. It's time complexity is O(log(n)^2).

function solve(n, k) {
   let binRep = [];
   let sumJugs = 0;
   while(n>0) {
      binRep.push(n%2);
      sumJugs += n%2;
      n = parseInt(n/2);
   }
   let cost = 0;
   while (sumJugs > k) {
      let idx = binRep.indexOf(1);
      cost += Math.pow(2, idx);
      while (binRep[idx] == 1 && idx < binRep.length) {
         sumJugs--;
         binRep[idx++] = 0;
      }
      if (idx >= binRep.length) binRep.push(1);
      else binRep[idx] = 1;
      sumJugs++;
   }
   return cost;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM