滴滴出行2017秋招笔试编程题(二)——地下迷宫、数字和为sum的方法数

这个题可以用dfs或bfs遍历迷宫,用dfs是递归地查看每一个位置,这里在每次走到一个前都要先查看青蛙的体力值够不够,不够的话,这条路就pass掉了,够的话继续往下遍历。递归结束的条件就是已经到达了出口,即[0][m-1]这个位置,当到达此位置时还要查看是否所消耗的体力是最少的。另一个问题是要记录最小路径,这里每到达一个位置就把它加入到一个数组中,位置不合适的话就把数组的下标-1,相当于把这个位置从最终路径中剔除掉。以下是dfs的代码:

public class maze {
	static int n,m,P;
	static int map[][] = new int[11][11];
	static int minPath[][] = new int[2][100];
	static int path[][] = new int[2][100];
	static int move[][] = new int[][]{{-1,0,3},{0,1,1},{1,0,0},{0,-1,1}};
	static int loseEnergy = 0;
	static int minLoseEnergy = Integer.MAX_VALUE;
	static int minSteps = 0;
	static int steps = 0;
	static int maxEnergy;
	public static void dfs(int row,int col,int[][] map){
		if(row == 0 && col == m - 1 && P >= loseEnergy){
			if(minLoseEnergy > loseEnergy){
				minLoseEnergy = loseEnergy;
				for(int i = 0; i < 2; i++)
					for(int j = 0; j < steps; j++)
						minPath[i][j] = path[i][j];
				minSteps = steps;
			}
		}
		for(int i = 0; i < 4; i++){
			int newRow = row + move[i][0];
			int newCol = col + move[i][1];
			if(newRow >= 0 && newRow < n && newCol >= 0 && newCol < m && map[newRow][newCol] == 1 && P >= loseEnergy){
				steps++;
				path[0][steps] = newRow;
				path[1][steps] = newCol;
				map[newRow][newCol] = 0;
				loseEnergy += move[i][2];
				dfs(newRow,newCol,map);
				map[newRow][newCol] = 1;
				steps--;
				loseEnergy -= move[i][2];
			}
		}
		
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin = new Scanner(System.in);
		n = cin.nextInt();
		m = cin.nextInt();
		P = cin.nextInt();
		for(int i = 0; i < n; i++)
			for(int j = 0; j < m; j++){
				map[i][j] = cin.nextInt();
			}
		cin.close();
		map[0][0] = 0;
		dfs(0,0,map);
		if(minLoseEnergy == Integer.MAX_VALUE)
			System.out.println("Can not escape!");
		else{
			for(int i = 0; i < minSteps; i++){
				System.out.print("["+ minPath[0][i] +","+ minPath[1][i] +"],");
			}
			System.out.print("[0," + (m-1) + "]");
		}
	}
}

看到这个题一下想到的是母函数和0/1背包

关于母函数的详细介绍参照博客http://blog.csdn.net/supersnow0622/article/details/9666871

以题目中的例子为例,代码模拟计算(1+X^5)*(1+X^5)*(1+X^10)*(1+X^2)*(1+X^3)则计算结果中X^15的系数就是方案数,这题还要注意大数问题。

代码如下:

public class motherFunction {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int n,sum,A[];
		Scanner cin = new Scanner(System.in);
		n = cin.nextInt();
		sum = cin.nextInt();
		A = new int[n];
		for(int i = 0; i < n ; i++){
			A[i] = cin.nextInt();
		}
		System.out.println(getTypeCount(n,sum,A));
	}
	//母函数解法
	public static BigInteger getTypeCount(int n,int sum,int[] A){
		BigInteger c[] = new BigInteger[1005];
		BigInteger c1[] = new BigInteger[1005];
		BigInteger c2[] = new BigInteger[1005];
		init(c);init(c1);init(c2);
		
		c1[0] = BigInteger.ONE;
		c1[A[0]] = BigInteger.ONE;
		for(int i = 1; i < n; i++){
			init(c2);
			init(c);
			int a = A[i];
			c2[0] = BigInteger.ONE;
			c2[a] = BigInteger.ONE;
			for(int j = 0; j <= sum; j++){
				if(c1[j] != BigInteger.ZERO){
					c[j] = c[j].add(c1[j].multiply(c2[0]));
					if(j + a <= sum)
						c[j + a] = c[j + a].add(c1[j].multiply(c2[a]));
				}
			}
			for(int k = 0; k <= sum; k++)
				c1[k] = c[k];
		}
		return c1[sum];
	}
	public static void init(BigInteger c[]){
		for(int i = 0;i < c.length; i++){
			c[i] = BigInteger.ZERO;
		}
	}
}

关于0/1背包计算方案数博客http://blog.csdn.net/supersnow0622/article/details/9772839#comments

在这个题中可以把每个数字当作物品的体积,和sum看作容器的体积,与一般的0/1背包不一样的地方是数组中存放的是和为i的方案数。

代码如下:

import java.math.BigInteger;
import java.util.Scanner;
public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int n,sum,A[];
		Scanner cin = new Scanner(System.in);
		n = cin.nextInt();
		sum = cin.nextInt();
		A = new int[n];
		for(int i = 0; i < n ; i++){
			A[i] = cin.nextInt();
		}
		System.out.println(getTypeCount1(n,sum,A));
	}
    public static BigInteger getTypeCount1(int n,int sum,int[] A){
		BigInteger c[] = new BigInteger[1005];
		for(int i = 1;i < c.length; i++){
			c[i] = BigInteger.ZERO;
		}
		c[0] = BigInteger.ONE;
		for(int i = 0;i < n; i++){
			int index = A[i];
			for(int j = sum; j >= 0; j--){
				if(j >= index && c[j-index]!=BigInteger.ZERO )
					c[j] = c[j].add(c[j-index]);
			}
		}
		return c[sum];
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值