【滴滴】2017滴滴(小青蛙的回溯题,背包0-1问题n个正整数的数组A和一个整数sum从后向前)

一个数组有 N 个元素,求连续子数组的最大和。 例如:[-1,2,1],和最大的连续子数组为[2,1],其和为 3

输入描述:

输入为两行。 第一行一个整数n(1 <= n <= 100000),表示一共有n个元素 第二行为n个数,即每个元素,每个整数都在32位int范围内。以空格分隔。

 

输出描述:

所有连续子数组中和最大的值。

示例1

输入

3 -1 2 1

输出

3

以前的和大于等于0,继续向下相加;以前的和小于0,从下一位重新开始相加,否则越加越小

import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        //连续子数组最大的和
        int num=s.nextInt();
        int []arr=new int[num];
        for(int i=0;i<num;i++){
            arr[i]=s.nextInt();
        }
        maxSum(arr);
 
    }
    public static void maxSum(int []arr){
        int max=arr[0];
        int sum=arr[0];
        for(int i=1;i<arr.length;i++){
            //以前的和大于0继续加,以前的和小于0重新赋值
            if(sum>=0){
                sum+=arr[i];
            }else{
                sum=arr[i];
            }
            if(sum>=max){
                max=sum;
            }
        }
        System.out.println(max);
    }
 
 
}

 

 

 

 

 

 

某餐馆有n张桌子,每张桌子有一个参数:a 可容纳的最大人数; 有m批客人,每批客人有两个参数:b人数,c预计消费金额。 在不允许拼桌的情况下,请实现一个算法选择其中一部分客人,使得总预计消费金额最大

输入描述:

输入包括m+2行。 第一行两个整数n(1 <= n <= 50000),m(1 <= m <= 50000) 第二行为n个参数a,即每个桌子可容纳的最大人数,以空格分隔,范围均在32位int范围内。 接下来m行,每行两个参数b,c。分别表示第i批客人的人数和预计消费金额,以空格分隔,范围均在32位int范围内。

 

输出描述:

输出一个整数,表示最大的总预计消费金额

示例1

输入

3 5 2 4 2 1 3 3 5 3 7 5 9 1 10

输出

20

对顾客按钱数排序,钱数相同的按人数排序,运行超时

import java.util.Scanner;
 
class Customer {
    int PeoNum;
    int Price;
}
 
public class Main {
 
    public static void main(String[] args) {
        //贪心算法(?)
        /*
         * 3 5 2 4 2 1 3 3 5 1 3 5 7 9 10
         */
        //4 6 12 1 4 7 11 3 3 10 35 10 5 9 12 10 6 7
        Scanner s = new Scanner(System.in);
        // 桌子个数N,来的客人M
        int N = s.nextInt();
        int M = s.nextInt();
        // 每张桌子的容量
        int[] table = new int[N];
        for (int i = 0; i < N; i++) {
            table[i] = s.nextInt();
        }
        //桌子大小从小到大排序
        // 人数和消费金额
        Customer[] customers = new Customer[M];
        for (int i = 0; i < M; i++) {
            customers[i] = new Customer();
            customers[i].PeoNum = s.nextInt();
            customers[i].Price = s.nextInt();
        }
        //顾客按照消费金额多少排序大到小,如果消费金额相等按照人数排序
        Customer temp=new Customer();
        for (int i = 0; i < M; i++) {
            for(int j=i;j<M;j++){
                if(customers[i].Price<customers[j].Price){
                    temp=customers[i];
                    customers[i]=customers[j];
                    customers[j]=temp;
                }
                if(customers[i].Price==customers[j].Price){
                    if(customers[i].PeoNum<customers[j].PeoNum){
                        temp=customers[i];
                        customers[i]=customers[j];
                        customers[j]=temp;
                    }
                }
            }
        }
         
        Restaurant(table, customers);
 
    }
 
    public static void Restaurant(int[] table, Customer[] customers) {
        // 记录每桌最大消费和剩余人数
        int[] maxPrice = new int[table.length];
        for (int i = 0; i < table.length; i++) {
            for (int j = 0; j < customers.length; j++) {
                if (table[i] >= customers[j].PeoNum) {
                    if(customers[j].Price>maxPrice[i]){
                        maxPrice[i]=customers[j].Price;
                        customers[j].PeoNum=Integer.MAX_VALUE;
                    }
                }
                 
            }
             
        }
        int sum = 0;
        for (int i = 0; i < maxPrice.length; i++) {
            //System.out.print(maxPrice[i]+" ");
            sum += maxPrice[i];
        }
        System.out.println(sum);
    }
 
}

 

 

 

 

 

 

小青蛙有一天不小心落入了一个地下迷宫,小青蛙希望用自己仅剩的体力值P跳出这个地下迷宫。为了让问题简单,假设这是一个n*m的格子迷宫,迷宫每个位置为0或者1,0代表这个位置有障碍物,小青蛙达到不了这个位置;1代表小青蛙可以达到的位置。小青蛙初始在(0,0)位置,地下迷宫的出口在(0,m-1)(保证这两个位置都是1,并且保证一定有起点到终点可达的路径),小青蛙在迷宫中水平移动一个单位距离需要消耗1点体力值,向上爬一个单位距离需要消耗3个单位的体力值,向下移动不消耗体力值,当小青蛙的体力值等于0的时候还没有到达出口,小青蛙将无法逃离迷宫。现在需要你帮助小青蛙计算出能否用仅剩的体力值跳出迷宫(即达到(0,m-1)位置)。

输入描述:

输入包括n+1行:
 第一行为三个整数n,m(3 <= m,n <= 10),P(1 <= P <= 100)
 接下来的n行:
 每行m个0或者1,以空格分隔

 

输出描述:

如果能逃离迷宫,则输出一行体力消耗最小的路径,输出格式见样例所示;如果不能逃离迷宫,则输出"Can not escape!"。 测试数据保证答案唯一

示例1

输入

4 4 10 1 0 0 1 1 1 0 1 0 1 1 1 0 0 1 1

输出

[0,0],[1,0],[1,1],[2,1],[2,2],[2,3],[1,3],[0,3]

回溯法!!,把可能的都走一遍然后选择需要能量最小的,记住最后需要把map[x][y]重新置为1,linkedlist也要把最后的remove掉

 

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Scanner;
 
public class Main {
    private static int m = 0, n = 0, minCost = Integer.MAX_VALUE, p = 0;
    private static LinkedList<Point> linkedList = new LinkedList<>();
    private static String path = "";
 
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        m = in.nextInt();
        p = in.nextInt();
        int[][] map = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                map[i][j] = in.nextInt();
            }
        }
         
        generate(map, 0, 0, 0);
        if (minCost == Integer.MAX_VALUE) {
            System.out.println("Can not escape!");
        } else {
            System.out.println(path.substring(0, path.length() - 1));
        }
    }
 
    private static void generate(int[][] map, int x, int y, int currentCost) {
        if (currentCost > p)
            return;
        map[x][y] = 2;
        linkedList.offer(new Point(x, y));
        if (x == 0 && y == m - 1) {
            if (currentCost < minCost) {
                minCost = currentCost;
                savePath();
            }
            map[x][y] = 1;
            linkedList.removeLast();
            return;
        }
        if (x < n - 1 && map[x + 1][y] == 1) {// down
            generate(map, x + 1, y, currentCost);
        }
        if (x > 0 && map[x - 1][y] == 1) {// up
            generate(map, x - 1, y, currentCost + 3);
        }
        if (y < m - 1 && map[x][y + 1] == 1) {// right
            generate(map, x, y + 1, currentCost + 1);
        }
        if (y > 0 && map[x][y - 1] == 1) {// left
            generate(map, x, y - 1, currentCost + 1);
        }
        map[x][y] = 1;
        linkedList.removeLast();
    }
 
    private static void savePath() {
        Iterator<Point> iterator = linkedList.iterator();
        StringBuilder sb = new StringBuilder();
        while (iterator.hasNext()) {
            Point point = iterator.next();
            sb.append("[").append(point.x).append(",").append(point.y).append("],");
        }
        path = sb.toString();
    }
 
    private static class Point {
        int x = 0;
        int y = 0;
 
        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
}

 

 

 自己改进的代码,感觉更加容易理解,调整了方法里代码的顺序以及一些细节。

import java.util.*;

public class Main {
	private static int m = 0, n = 0, minCost = Integer.MAX_VALUE, p = 0;
	private static ArrayList<Point> list = new ArrayList<>();
	public static ArrayList<Point> minlist;

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		n = in.nextInt();
		m = in.nextInt();
		p = in.nextInt();
		int[][] map = new int[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				map[i][j] = in.nextInt();
			}
		}

		generate(map, 0, 0, 0);
		if (minCost == Integer.MAX_VALUE) {
			System.out.println("Can not escape!");
		} else {
			for(int i=0;i<minlist.size()-1;i++){
				System.out.print("["+minlist.get(i).x+","+minlist.get(i).y+"]"+",");
				
			}
			System.out.println("["+minlist.get(minlist.size()-1).x+","+minlist.get(minlist.size()-1).y+"]");
		}
	}

	private static void generate(int[][] map, int x, int y, int currentCost) {
		//花费体力超过所给的体力
		if (currentCost > p) {
			return;
		}
		if (x == 0 && y == m - 1) {
			if (currentCost < minCost) {
				minCost = currentCost;
				//把最短路径存起来
				minlist=new ArrayList<>(list);
				//最短路径再加上终点
				minlist.add(new Point(0, m-1));
			}
			return;
		}
		
		
		//标记走过的点,并存入list
		map[x][y] = 2;
		list.add(new Point(x, y));
		//递归
		if (x < n - 1 && map[x + 1][y] == 1) {// down
			generate(map, x + 1, y, currentCost);
		}
		if (x > 0 && map[x - 1][y] == 1) {// up
			generate(map, x - 1, y, currentCost + 3);
		}
		if (y < m - 1 && map[x][y + 1] == 1) {// right
			generate(map, x, y + 1, currentCost + 1);
		}
		if (y > 0 && map[x][y - 1] == 1) {// left
			generate(map, x, y - 1, currentCost + 1);
		}
		//移出点
		map[x][y] = 1;
		list.remove(list.size()-1);
	}


	private static class Point {
		int x = 0;
		int y = 0;

		Point(int x, int y) {
			this.x = x;
			this.y = y;
		}
	}
}

 

 

输入一个正整数n,求n!(即阶乘)末尾有多少个0? 比如: n = 10; n! = 3628800,所以答案为2

输入描述:

输入为一行,n(1 ≤ n ≤ 1000)

 

输出描述:

输出一个整数,即题目所求

示例1

输入

10

输出

2

 

 

分析:https://blog.csdn.net/shubingzhuoxue/article/details/52575999

对N进行质因数分解 N=2^x * 3^y * 5^z...,由于10 = 2*5,所以末尾0的个数只和x与z有关,每一对2和5相乘可以得到一个10,于是末尾0的个数=min(x,z)。在实际中x是远远大于z的,所以我们只要求出z的值即可。
  根据公式
  z = N/5 + N/5^2 + N/5^3+...+N/5^k
  这表明,5的倍数贡献了一个5,5^2的倍数又贡献了一个5...。

  比如:25其实是贡献了2个5,但是在N/5中已经贡献了一个,所以在N/5^2中再贡献一个;同样,125在N/5中贡献一个,在N/5^2中贡献一个,在N/5^3中再贡献一个,一共是3个。

import java.util.Scanner;
 
public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int num=sc.nextInt();
        //countZero=N/5+N/5/5+N/5/5/5+...[直到N为0截止]
        int countZero=0;
        while(num>0){
            countZero+=num/5;
            num=num/5;
        }
        System.out.println(countZero);
    }
 
}

 

 

 

 

 

 

 

 

给定一个十进制数M,以及需要转换的进制数N。将十进制数M转化为N进制数

输入描述:

输入为一行,M(32位整数)、N(2 ≤ N ≤ 16),以空格隔开。

 

输出描述:

为每个测试实例输出转换后的数,每个输出占一行。如果N大于9,则对应的数字规则参考16进制(比如,10用A表示,等等)

示例1

输入

7 2

输出

111

 

进制转换,不难,但是需要考虑负数

import java.util.*;
 
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();
        int N = sc.nextInt();
        int M = 0;
        // 如果M是负数,把他变成正数求
        if (m < 0) {
            M = -m;
        } else {
            M = m;
        }
 
        List list = new ArrayList();
        while (M / N != 0) {
            list.add(Switch(M % N));
            M = M / N;
        }
        list.add(Switch(M % N));
        if (m < 0) {
            list.add('-');//负数前面加负号
        }
        for (int i = list.size() - 1; i >= 0; i--) {
            System.out.print(list.get(i));
        }
 
    }
 
    public static char Switch(int m) {
        char result = ' ';
        // 大写字母A的asc码65
        int plus = 65;
        // 小于9直接返回
        if (m <= 9) {
            return (char) (m + 48);
        }
        plus += m - 10;
        result = (char) plus;
        return result;
    }
 
}

 

 

 

 

 

 

给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数。

当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案。 

 

输入描述:

输入为两行:
 第一行为两个正整数n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000)
 第二行为n个正整数A[i](32位整数),以空格隔开。

 

输出描述:

输出所求的方案数

示例1

输入

5 15 5 5 10 2 3

输出

4

这道题要跟2017美团的钱的那道题区分开,看起来很相似;但是那个组成部分可以重复,这个不可以;那个内层循环是从前向后,这个是从后向前,否则会算多了,这个属于背包0-1问题

import java.util.*;
 
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int sum = in.nextInt();
        int[] value = new int[n];
        long[] dp = new long[sum + 1];
        dp[0] = 1;
        for (int i = 0; i < n; i++) {
            value[i] = in.nextInt();
        }
        for (int i = 0; i < n; i++) {
            for (int j = sum; j >=value[i]; j--) {
                dp[j] += dp[j - value[i]];
            }
//          for(int k=0;k<dp.length;k++){
//              System.out.print(dp[k]+" ");
//          }
//          System.out.println();
        }
        System.out.println(dp[sum]);
 
    }
 
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值