Cattle customer network algorithm Summary (3)

A: greedy algorithm

1. bullion points

A bullion cut in half, and takes a value the same as the length of the copper plate. For example, a length of 20 gold bars, cut into two halves regardless of how much length, must spend 20 copper. A group of people who want to divide the entire block of gold bullion, how to divide the province most copper?

For example, given the array {10, 20}, representing a total of three, the entire length of bars 10 + 20 + 30 = 60. Bullion to be divided into three parts 10,20,30. If the length of the first bars 10 and 60 into 50, 60 takes the bars 50 and then into a length of 20 and 30, a total cost spent 50 110 copper.
If, however, the length of the first bars 30 and 60 into 30, 60 then take a length of bars 30 and 20 into 10, 30 spent a total of 90 spent copper.
An input array, divided returns minimum cost.


/**
 * 分金条,求最小代价和,可以使用哈弗曼树来做
 */
public class GoldBullion {

    private static class Node implements Comparable<Node> {
        public Node(Integer value) {
            this.value = value;
        }

        public Integer value;
        public Node parent;
        public Node left;
        public Node right;

        public boolean isLeaf() {
            return left == null && right == null;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((value == null) ? 0 : value.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Node other = (Node) obj;
            if (value == null) {
                if (other.value != null)
                    return false;
            } else if (!value.equals(other.value))
                return false;
            return true;
        }

        @Override
        public int compareTo(Node o) {
            return this.value - o.value;
        }
    }

    private static PriorityQueue<Node> pq = new PriorityQueue<>();

    private static int sum;

	//分金条的过程,就是构造哈弗曼树的过程
	//当哈弗曼树构造好,根节点就是金条的总长度,叶子节点就是想分出的小金条长度
	//叶子节点的路径权重和就是划分所需要的代价

    public static int bull(int[] input) {
        //初始化多个树
        for (int i = 0; i < input.length; i++) {
            pq.add(new Node(input[i]));
        }
        //开始创建
        while (pq.size() > 1) {
            Node left= pq.poll();
            Node right = pq.poll();
            Node parent = new Node(left.value+right.value);
            parent.left = left;
            parent.right = right;
            pq.add(parent);
        }
        Node root = pq.poll();
        return count(root,0);
    }

	//从哈弗曼树求出所有叶子节点的路径权值和
    private static int count(Node node,int count){
        if (node == null)
            return 0;
        if (node.isLeaf())
            sum += count* node.value;
        else
        {
            if (node.left != null)
                count(node.left,count+1);
            if (node.right != null)
                count(node.right,count+1);
        }
        return sum;
    }

    public static void main(String[] args) {
        int[] arr = {10,20,30};
        System.out.println(bull(arr));
    }
}

Method 2:

public static int bull2(int[] arr){
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        for (int i = 0; i < arr.length; i++) {
            queue.add(arr[i]);
        }
        int count = 0;
        while (queue.size() > 1)
        {
            int a = queue.poll();
            int b = queue.poll();
            int sum = a + b;
            queue.add(sum);
            count += sum;
        }
        return count;
    }

2. do the project

Input: parameter 1, parameter 2 n number of arrays costs, profits positive parameter array 3, 4 positive parameter k, the number of positive m

costs [i] represents the number of project i take
profits [i] i represents the number of items after the deduction of cost but also earn money (profit)
k parallel that you can not only do most k items serial
m represents you initial funding
Note: every time you finish a project and immediately gains that can support you to do the next project.

Output: maximum money you finally get the number.

/**
 * 做项目
 */
public class ProjectTest {

    //封装数据项
    static class Process implements Comparable{
        int cost;
        int profit;

        public Process(int cost, int profit) {
            this.cost = cost;
            this.profit = profit;
        }

        @Override
        public int compareTo(Object o) {
            return this.cost - ((Process)o).cost;
        }
    }

    //实现两个堆,代价的最小堆和收益的最大堆
    //我们希望在花费最小代价的情况下获得最大收益

    static class CostComparator implements Comparator<Process>{

        @Override
        public int compare(Process o1, Process o2) {
            return o1.cost - o2.cost;
        }
    }

    static class ProfitComparator implements Comparator<Process>{

        @Override
        public int compare(Process o1, Process o2) {
            return o2.profit - o1.profit;
        }
    }

    static PriorityQueue<Process> costQueue = new PriorityQueue<>(new CostComparator());
    static PriorityQueue<Process> profitQueue = new PriorityQueue<>(new ProfitComparator());


    public static int doProject(int[] costs,int[] profits,int k,int m){
        //初始化代价堆
        for (int i = 0; i < costs.length; i++) {
            Process process = new Process(costs[i],profits[i]);
            costQueue.add(process);
        }
        //在不超出工程步骤的情况下
        for (int i = 0; i < k; i++) {
            //找出能够接受的项目
            while (!costQueue.isEmpty() && costQueue.peek().cost <= m)
                profitQueue.add(costQueue.poll());
            //在这些项目中找到最大收益
            if (profitQueue.isEmpty())
                return m;
            m += profitQueue.poll().profit;
        }
        return m;
    }

    public static void main(String[] args) {
        int[]c = new int[]{10,20,100};
        int[]p = new int[]{11,10,200};
        System.out.println(doProject(c,p,c.length,50));//71
    }

}

3. Organization of activities

Some projects take up a conference room preach, preach meeting room can not accommodate both projects at the same time. Each time you start a project and end time (to give you an array, which is a concrete project), you preach to arrange the schedule, conference room requires the screening of up to preach. Returns the most preaching sessions.

public class ActivityTest {
    //数据项
    static class Activity implements Comparable{
        int index;
        int start;
        int end;

        public Activity(int index, int start, int end) {
            this.index = index;
            this.start = start;
            this.end = end;
        }

        @Override
        public String toString() {
            return "Activity{" +
                    "index=" + index +
                    ", start=" + start +
                    ", end=" + end +
                    '}';
        }

        @Override
        public int compareTo(Object o) {
            return this.end - ((Activity)o).end;
        }
    }

    private static PriorityQueue<Activity> endQueue = new PriorityQueue<>();

    public static int select(int[] start,int[] end){
        Activity[] activities = new Activity[start.length];
        for (int i = 0; i < start.length; i++) {
            Activity activity = new Activity(i,start[i],end[i]);
            activities[i] = activity;
        }
        endQueue.addAll(Arrays.asList(activities));
        //初始化场次
        int count = 0;

        //选出最早下课时间
        while (!endQueue.isEmpty()){
            Activity last = endQueue.poll();
            count++;
            //下一次上课时间应该比上一次上课的时间晚
            while (!endQueue.isEmpty() && endQueue.peek().start < last.end)
                endQueue.poll();
        }
        return count;

    }

    public static void main(String[] args) {
        int start[] = {1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12};
        int end[] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
        System.out.println(select(start,end));
    }
}

II: Recursive

1. seeking n! Results

    //计算阶乘
    public static int fac(int n){
        if(n <= 1)
            return n;
        return n*fac(n-1);
    }

2. Tower of Hanoi problem

N-layer printed HANOR moving the entire process from the leftmost rightmost

    public static void move(int n,char from, char temp,char to){
    	//只有一个,直接移动
        if(n == 1)         
        {
            System.out.printf("move the %d :%s-->%s%n",n,from,to);
        }
        else
        {
            move(n-1,from,to,temp);     //把A塔上编号1~n-1的圆盘移动到辅助盘上
            System.out.printf("move the %d :%s-->%s%n",n,from,to);  // 把最后一个圆盘直接移动到目标盘
            move(n-1,temp,from,to);     //再把1~n-1的圆盘移到目标盘回来
        }
    }

3. Print string

Printing a string of all substrings

/**
 * 打印字符串的所有子串
 */
public class StringTest {
    public static void printAllSubString(String s){
        if (s == null)
            return;
        int low = 0;
        int high = s.length();
        printAllSubString(s,low,high);
    }
    private static void printAllSubString(String s, int start,int end) {
        if (start == s.length())
            return;
        if (end == s.length() + 1) {
            printAllSubString(s,start + 1,start + 2);
        }
        else {
            System.out.printf("%s ", s.substring(start,end));
            printAllSubString(s, start, end + 1);
        }
    }

    public static void main(String[] args) {
        String s = "abcd";
        printAllSubString(s);
    }

}

All sequences printing a character string, including the null string (all combinations)

    //全部子序列
    public static void printAllSubSequence(String s){
        char[] chars = s.toCharArray();
        int index = 0;
        printAllSubSequence(chars,“”,index);
    }

    private static void printAllSubSequence(char[] s,String res,int index) {
//        if (index == s.length) {
//            String temp = String.valueOf(s);
//            System.out.printf("%s ", temp);
//            return;
//        }
        if (index == s.length) {
            //避免重复
            String temp = res.trim();
            if (!set.contains(temp))
            {
                set.add(temp);
                System.out.printf("%s ", temp);
            }
            return;
        }
        //我想要当前字符
        printAllSubSequence(s,res+s[index],index + 1);

        //我不想要当前字符
        printAllSubSequence(s,res,index + 1);
    }


Printing all permutations of a string, not duplicate arrangement requires

    //全排列,每个节点 i 有  n - i 种选择
    public static void printAllPermutations(String str) {
        char[] chs = str.toCharArray();
        printAllPermutations(chs, 0);
    }


    private static void printAllPermutations(char[] chs, int i) {
        //无法与最后的字符交换,打印
        if (i == chs.length) {
                System.out.printf("%s ",String.valueOf(chs));
        }
        // 用于保证每次交换的字符不存在重复的字符
        HashSet<Character> set1 = new HashSet<>();
        //依次与后面的字符交换
        for (int j = i; j < chs.length; j++) {
            //防止重复
            if (!set1.contains(chs[j])){
                set1.add(chs[j]);
                //我想要第j个字符
                swap(chs, i, j);
                printAllPermutations(chs, i + 1);
                //我不想要第j个字符
                swap(chs, i, j);
            }
//            //我想要第j个字符
//            swap(chs, i, j);
//            printAllPermutations(chs, i + 1);
//            //我不想要第j个字符
//            swap(chs, i, j);
        }
    }

4. cow problem

Cow a cow born each year, the growth of the new-born cow after three years can be a raw cow per year, assuming that will not die. After seeking N, the number of cows.

 public int noDeath(int i){
        if (i <= 0)
            return 0;
        //因为一头牛需要3年才能生,所以前3年都是不生的,有几头牛就只有几头牛,他们不能再生了
        else if (i <= 3)
            return i;
        //如果超过3年,那么可以先看看上一年剩下的牛,再加上除了近3年生不了的牛,3年前的牛他们还能再生
        return noDeath(i-1) + noDeath(i-3);
    }

If each cow can live 10 years, seeking N, the number of cows

    public static int death(int i,int year){
        if (i <= 0)
            return 0;
            //因为一头牛需要3年才能生,所以前3年都是不生的,有几头牛就只有几头牛,他们不能再生了
        else if (i <= 3)
            return i;
        //如果还未超过死亡期限,则按照上一方法处理
        else if (i <= year)
            return noDeath(i);
        //如果到达死亡期限,可以先看看没死的时候应该有多少牛,再减去死掉的牛个数
        return death(i-1,year) + death(i-3,year) - death(i - year,year);
    }

5. give you a stack, you reverse the stack, you can not apply for additional data structure, only use a recursive function. How to achieve?

/**
 * 逆序栈
 */
public class ReverseStack {
    //这个函数递归栈用于存储最后一个元素
    public static void reverse(Stack<Integer> stack){
        if (stack.isEmpty())
            return;
        //从栈底到栈顶出栈-->进入辅助栈
        int last = getLast(stack);
        reverse(stack);
        //从栈顶到栈底入栈-->从辅助栈出来
        stack.push(last);
    }

    //这个函数递归栈用于存储其他 元素
    //获取栈底
    public static int getLast(Stack<Integer> stack){
        int res = stack.pop();
        //只剩一个,直接返回
        if (stack.isEmpty())
            return res;
        else {
            //从栈顶到栈底出栈-->进入辅助栈
            int last = getLast(stack);
            //把除了最后一个的其他入栈-->离开辅助栈
            stack.push(res);
            return last;
        }
    }
}

Three: dynamic programming (de-duplication, no after-effect)

  1. The number of variable parameters, determining N-dimensional table
  2. Determining a variable parameter range, the range determining table
  3. Determining a target parameter, and marked in the table
  4. The final determination of the parameters may be determined, marked in the table
  5. He began to fill in a form from the border, to fill out all values ​​can be determined
  6. Back to normal recursive function, fill in a form

1. The minimum path and

Give you a two-dimensional array, each two-dimensional array of numbers are positive, go to the lower right corner from the top left corner of requirements, each step can only be to the right or down. Along the way through to the number to add up. And a minimum return path.

Recursive approach

    public static int min(int[][] matrix){
        return min(matrix,0,0,matrix[0].length - 1,matrix.length - 1);
    }

    public static int min(int[][] matrix,int x1,int y1,int x2,int y2){
        //走到最下面,则向右走
        if (y1 > y2)
            return min(matrix, x1 + 1, y2, x2, y2);
        //走到最右边,则向下走
        if (x1 > x2)
            return min(matrix, x2, y1 + 1, x2, y2);
        //走到终点,返回
        if (x1 == x2 && y1 == y2)
            return matrix[y2][x2];

        //每个点有两个选择:向右尝试,向下尝试
        //再取最小值
        int temp1 =  matrix[y1][x1] + min(matrix, x1 + 1, y1, x2, y2);
        int temp2 =  matrix[y1][x1] + min(matrix, x1, y1 + 1, x2, y2);
        return Math.min(temp1,temp2);
    }

Dynamic programming approach:

    //动态规划
    public static int minDP(int[][] matrix){
        int row = matrix.length - 1;
        int col = matrix[0].length - 1;
        //缓存表
        int[][] dp = new int[row+1][col+1];
        //边界值
        dp[row][col] = matrix[row][col];
        //填充最后一列
        for (int i = row - 1; i >= 0; i--) {
            dp[i][col] = dp[i + 1][col] + matrix[i][col];
        }
        //填充最后一行
        for (int i = col - 1; i >= 0; i--) {
            dp[row][i] = dp[row][i + 1] + matrix[row][i];
        }
        //填充表格
        for (int i = row - 1; i >= 0; i--) {
            for (int j = col - 1; j >= 0; j--) {
                dp[i][j] = Math.min(dp[i + 1][j],dp[i][j + 1]) + matrix[i][j];
            }
        }
        //目标值
        return dp[0][0];
    }

2. cumulative array

Given an array ARR, and returns all accumulated in the sub-array, and the maximum cumulative

    //递归
    public static int max2(int[] arr){
        if (arr.length < 1)
            return 0;
        return max2(arr,0,1);
    }
    private static int max2(int[] arr, int start,int end) {
        if (start == arr.length){
           return 0;
        }
        if (end == arr.length + 1)
            return max2(arr,start + 1,start + 2);
        int sum = 0;
        for (int i = start; i < end; i++) {
            sum += arr[i];
        }
        return Math.max(sum,max2(arr,start,end + 1));
    }

    //迭代
    public static int maxSubArray(int[] arr) {
        if (arr == null || arr.length == 0) {
            return 0;
        }
        int cur = 0;
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < arr.length; i++) {
            cur += arr[i];
            max = Math.max(cur, max);
            if (cur < 0) {
                cur = 0;
            }
        }
        return max;
    }

    //动态规划
    public static int max2(int[] arr){
        int len = arr.length - 1;
        //变化的参数只有一个——索引,建立一维数组
        int[] dp = new int[len + 1];
        //已知最后一个元素
        dp[len] = arr[len];
        //开始填表,把相对较大和的数填入
        for (int i = len - 1; i >= 0; i--)
            
            dp[i] = Math.max(arr[i] + dp[i + 1],dp[i + 1]);
        //目标是第0个元素
        return dp[0];
    }

To give you an integer aim, can not get accumulated aim, returns true or false

    //递归
    public static boolean isSum(int[] arr,int aim){
        return isSum(arr,0,0,aim);
    }
    public static boolean isSum(int[] arr,int index,int sum,int aim){

        //从头开始迭代,直接到数组尾部
        if (index == arr.length)
            return  sum == aim;
        //选择要当前的数
        boolean temp1 = isSum(arr, index + 1, sum + arr[index], aim);
        //选择不要当前的数
        boolean temp2 = isSum(arr, index + 1, sum, aim);

        return temp1 || temp2;
    }

    //动态规划
    private static boolean isSumDP(int[] arr,int aim){
        int len = arr.length;
        int sum = 0;
        for (int i = 0; i < len; i++) {
            sum += arr[i];
        }
        if (sum < aim)
            return false;
        //根据数组的长度和最大和,建立缓存表
        boolean[][] dp = new boolean[len + 1][sum + 1];
        //最后一行是确定值,先填充
        for (int i = 0; i <= sum; i++) {
            dp[len][i] = i == aim;
        }
        //从最后一行向上,开始填充普通值
        for (int i = len - 1; i >= 0; i--) {
            for (int j = sum; j >= 0; j--) {
                //可以选择当前值或者不选择当前值
                if (arr[i] + j <= sum)
                    dp[i][j] = dp[i + 1][j] || dp[i + 1][arr[i] + j];
                //无法选择当前值,因为他之前已经被选了
                else
                    dp[i][j] = dp[i + 1][j];
            }
        }

        return dp[0][0];
    }

There is a negative number:

    private static boolean isSumDP1(int[] arr,int aim){
        int len = arr.length;
        int min = 0,max = 0;
        //统计最小值与最大值
        for (int i = 0; i < len; i++) {
            if (arr[i] >= 0)
                max += arr[i];
            else
                min += arr[i];
        }
        if (max < aim || min > aim)
            return false;
        //根据数组的长度和最大和,建立缓存表
        boolean[][] dp = new boolean[len + 1][Math.abs(min) + max + 1];
        //最后一行是确定值,先填充
        for (int i = 0,j = min; i <= Math.abs(min) + max; i++,j++) {
            dp[len][i] = j == aim;
        }
        //从最后一行向上,开始填充普通值
        for (int i = len - 1; i >= 0; i--) {
            for (int j = Math.abs(min) + max; j >= 0; j--) {
                //可以选择当前值或者不选择当前值
                if (arr[i] + j <= Math.abs(min) + max && arr[i] + j >= 0)
                    dp[i][j] = dp[i + 1][j] || dp[i + 1][arr[i] + j];
                //无法选择当前值,因为他之前已经被选了
                else
                    dp[i][j] = dp[i + 1][j];
            }
        }
        //目标是第“(0,0)”个,也就是偏移min个负数后的位置
        return dp[0][Math.abs(min)];
    }

3. knapsack problem

Given two arrays w and v, two arrays are equal in length, w [i] represents the weight of the items i, v [i] denotes the i-th value of the items. Give a fixed integer bag, require you to select items combined weight must not exceed the bag, return the greatest value to satisfy this condition, you can get.

    //递归
    public static int maxValue(int[] w,int[] v,int bag){
        return maxValue(w, v, bag,0,0,0);
    }
    public static int maxValue(int[] w,int[] v,int bag,int index,int weight,int value){

        //如果当前重量太重了,或者没有物品了,就不放入,返回当前价值
        if (index == w.length || weight + w[index] > bag)
            return value;
        //选择要当前的数
        int yes = maxValue(w, v, bag, index+1,weight + w[index],value + v[index]);
        //选择不要当前的数
        int no = maxValue(w, v, bag, index+1,weight,value);
        //获得最大的价值
        return Math.max(yes,no);
    }

    //动态规划
    public static int maxValueDP(int[] w, int[] v, int bag) {
        int len = w.length;
        //参数变化的有重量和物品的个数。以此建立表,并记录价值
        int[][] dp = new int[len + 1][bag + 1];
        //最后一
        for (int i = 0; i < len; i++) {
            dp[i][bag] = v[i];
        }
        for (int i = len - 1; i >= 0; i--) {
            for (int j = bag; j >= 0; j--) {

                //可以选择当前值或者不选择当前值
                if (w[i] + j <= bag)
                    dp[i][j] = Math.max(dp[i + 1][j], v[i] + dp[i + 1][w[i] + j]);
                else
                    dp[i][j] = dp[i + 1][j];

            }
        }

        for (int i = 0; i < dp.length; i++) {
            for (int j = 0; j < dp[0].length; j++) {
                System.out.print(dp[i][j] + "\t");
            }
            System.out.println();
        }
        //目标是第“(0,0)”个,也就是偏移min个负数后的位置
        return dp[0][0];
    }

Guess you like

Origin blog.csdn.net/weixin_36904568/article/details/94457900