A. 牛牛分蛋糕

解题思路:二分
这道题我写了一个二分的思路,这个问题是具有二段性的,就是二分出蛋糕最少的那个盘子中的蛋糕数最多为多少,然后让所有剩余的盘子的蛋糕数都为这个数字,判断是否可以,如果可以则收缩左边界。

参考代码1

import java.util.*;


public class Solution {
    /**
     * 处理函数,返回在所有分法中,蛋糕数量最少的盘子中分到最多的蛋糕数量
     * @param n int整型 n个盘子
     * @param a int整型 a蛋糕数量
     * @param b int整型 b蛋糕数量
     * @return int整型
     */
    boolean check(int v, int a, int b, int n){
         return a / v + b / v >= n;
    }

    public int solve (int n, int a, int b) {
        // write code here

        int r = Math.max(a, b);
        int l = 1;

        while(l < r){
            int mid = l + r + 1>> 1;
            if(!check(mid, a, b, n)) r = mid - 1;
            else l = mid;
        }

        return l;
    }
}

解题思路2: 枚举
可以发现,最终一定会是a的蛋糕给几个盘子,b的蛋糕给几个盘子,所以我们可以枚举a蛋糕分配的盘子数和b蛋糕分配的盘子数,找到一个使得最少蛋糕的盘子的蛋糕最多的分配方案即可。

参考代码2

import java.util.*;


public class Solution {
    /**
     * 处理函数,返回在所有分法中,蛋糕数量最少的盘子中分到最多的蛋糕数量
     * @param n int整型 n个盘子
     * @param a int整型 a蛋糕数量
     * @param b int整型 b蛋糕数量
     * @return int整型
     */
    public int solve (int n, int a, int b) {
        // write code here
        int ans = 1;

        for(int i=1; i<n; i++){
            int one = a / i;
            int two = b / (n - i);

            ans = Math.max(ans, Math.min(one, two));
        }

        return ans;
    }
}


B.牛牛凑数字

解题思路
这道题是使用贪心的思路,觉得遇到这种拼接数字使得数字最大的问题,应该是这样来贪才对,就是先要保证长度最长,然后剩余的钱买更大的数字来对前面的一些数字进行替换,这样得到的数字才是最大的,在这道题中,也就是先用给定的钱买价值最小的且数字最大的数字,保证长度最长,然后用剩下的钱从当前形成的字符串的首端开始,用某个可以买起的最大的数字来对当前数字进行替换就好了。

需要注意的是,java的话要使用StringBuilder,因为String拼接字符串的速度巨慢!!

参考代码

import java.util.*;


public class Solution {
    /**
     * 得到牛牛能够凑到的最大的数字
     * @param n int整型 牛牛能够承受的价格
     * @param a int整型一维数组 1-9这九个数字的价格数组
     * @return string字符串
     */
    public String solve (int n, int[] a) {
        // write code here
        int min = 0x3f3f3f3f;
        int k = -1; // 代表价值最小的数字是几

        for(int i=0; i<9; i++) {
            if(a[i] <= min) {
                min = a[i];
                k = i + 1;
            }
        }

        if(n < min) return  "-1";
        int max_len = n / min; // 获取结果的最大长度
        int left = n % min; // 获取剩余的钱数

        char[] res = new char[max_len];
        char c = (char)(k + (int)'0');
        Arrays.fill(res, c);

        int idx = 0; // 指针
        while(left != 0) {
            left += min;

            boolean flag = false;
            for(int i=8; i>=0; i--) {
                if(left >= a[i]) {
                    res[idx] = (char)((i + 1) + (int)'0');
                    flag = true;
                    left -= a[i];
                    break;
                }
            }

            idx ++;
            if(idx == max_len || !flag) break;
        }

        StringBuffer s = new StringBuffer();
        for(int i=0; i<max_len; i++) s.append(res[i]);

        return s.toString();
    }
}


C.牛妹的野菜

解题思路
由于这张图是一张拓扑图,且要求最大,故自然而然想到DP,这里我们定义dp[i]表示以i为起点的获得番薯的最大值,状态转移方程为dp[i] = max(dp[u] + w[i]),这里ui的所有子节点,另外需要注意这道题要输出方案,所以使用一个next数组记录每一个节点是由哪一个点转移过来的就可以了。

参考代码

import java.util.*;


public class Solution {
    int N = 310, M = N * N;
    int[] dp = new int[N]; // 表示以某个点作为起点的最大收益
    int[] next = new int[N]; // 保存每一个番薯洞穴的下一个位置
    int[] h = new int[N];
    int[] e = new int[M];
    int[] ne = new int[M];
    int[] w = new int[M];
    int idx;

    void add(int a, int b, int c) {
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx ++;
    }

    int dfs(int u, int[] w){
        if(dp[u] != -1) return dp[u];

        dp[u] = w[u - 1];
        for(int i=h[u]; i!=-1; i=ne[i]){
            int j = e[i];

            dfs(j, w);

            if(dp[j] + w[u - 1] > dp[u]){
                next[u] = j;
                dp[u] = dp[j] + w[u - 1];
            }
        }

        return dp[u];
    } 

    public String digSum (int[] potatoNum, int[][] connectRoad) {
        // write code here

        Arrays.fill(dp, -1);
        Arrays.fill(next, -1);

        int n = potatoNum.length;

        Arrays.fill(h, -1);

        for(int[] cur : connectRoad) {
            add(cur[0], cur[1], potatoNum[cur[1] - 1]);
        }

        for(int i=1; i<=n; i++) dfs(i, potatoNum);

        int idx = 1;
        for(int i=1; i<=n; i++){
            if(dp[i] > dp[idx]){
                idx =  i;
            }
        }

        String res = "";
        while(idx != -1){
            if(next[idx] != -1) res += idx + "-";
            else res += idx;
            idx = next[idx];
        }

        return res;
    }
}