每日一题20220607

  1. 大妈一开始手上有x个鸡蛋,她想让手上的鸡蛋数量变成y,
    操作1 : 从仓库里拿出1个鸡蛋到手上,x变成x+1个,
    操作2 : 如果手上的鸡蛋数量是3的整数倍,大妈可以直接把三分之二的鸡蛋放回仓库,手里留下三分之一。
    返回从x到y的最小操作次数。
    1 <= x,y <= 10^18。
    ————————————————
    版权声明:本文为CSDN博主「福大大架构师每日一题」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_48502062/article/details/125155668
 /**
     * 求解x->y最少的次数
     * @param x
     * @param y
     * @return
     */
    public static int minTime(int x,int y){
        if (x<=y){
            return y-x;
        }
        int mod = x%3;
        //要凑齐到3的倍数要花费的行动点数
        int need = mod ==0?0:(mod==1?2:1);
        //每次都尽可能的增加现有最大的鸡蛋数量
        return need+1+minTime((x+2)/3,y);
    }
    /**
     * 优化方案
     * @param x
     * @param y
     * @return
     */
    public static int minTimePlus(int x,int y){
        if (x<=y){
            return y-x;
        }
        //这个限制目前认为最好的
        int limit = minTime(x,y);
        //新建一个dp数组来进行存储递归过程中出现的次数
        int[][] dp = new int[x+1+limit][limit+1];
        return process(x,y,0,limit,dp);
    }

    /**
     *
     * @param cur 当前的鸡蛋数量
     * @param aim 目标的鸡蛋数量
     * @param pre 之前已经用了多少行动点数
     * @param limit 一定的行动数,超过就放弃
     * @param dp dp数组
     * @return
     */
    private static int process(int cur, int aim, int pre, int limit, int[][] dp) {
        if (pre>limit){
            return Integer.MAX_VALUE;
        }
        if (dp[cur][pre] !=0){
            return dp[cur][pre];
        }
        int ans = 0;
        if (cur==aim){
            return pre;
        }else {
            int p1 = process(cur+1,aim,pre+1,limit,dp);
            int p2 = Integer.MAX_VALUE;
            if (cur%3==0){
                p2 = process(cur/3,aim,pre+1,limit,dp);
            }
            ans = Math.min(p1,p2);
        }
        //往回进行更新
        dp[cur][pre] = ans;
        return ans;
    }
posted @ 2022-06-07 14:01  一棵小萌新  阅读(23)  评论(0)    收藏  举报