网易2017实习编程题



一种双核CPU的两个核能够同时的处理任务,现在有n个已知数据量的任务需要交给CPU处理,假设已知CPU的每个核1秒可以处理1kb,每个核同时只能处理一项任务。n个任务可以按照任意顺序放入CPU进行处理,现在需要设计一个方案让CPU处理完这批任务所需的时间最少,求这个最小的时间。 

输入描述:
输入包括两行:
第一行为整数n(1 ≤ n ≤ 50)
第二行为n个整数length[i](1024 ≤ length[i] ≤ 4194304),表示每个任务的长度为length[i]kb,每个数均为1024的倍数。


输出描述:
输出一个整数,表示最少需要处理的时间

输入例子:
5
3072 3072 7168 3072 1024

输出例子:
9216

思路:等价于求最接近总和一半的数,也就等价于一个容量为总和一半的背包问题

public class Main {
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()) {
			int n = sc.nextInt();
			int[]a=new int[n];
			for(int i=0; i<n; i++)a[i]=sc.nextInt()/1024;
			int sum=0;
			for(int i:a)sum+=i;
			int target = sum/2;
			
			// pack algorithm
			int[][] dp = new int[n+1][target+1];
			for(int i=1; i<=n; i++)
				for(int j=1; j<=target; j++)
					if(j >= a[i-1])
						dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-a[i-1]]+a[i-1]);
					else
						dp[i][j] = dp[i-1][j];
			
			System.out.println((sum-dp[n][target])*1024);
		}
	}

}








小易拥有一个拥有魔力的手环上面有n个数字(构成一个环),当这个魔力手环每次使用魔力的时候就会发生一种奇特的变化:每个数字会变成自己跟后面一个数字的和(最后一个数字的后面一个数字是第一个),一旦某个位置的数字大于等于100就马上对100取模(比如某个位置变为103,就会自动变为3).现在给出这个魔力手环的构成,请你计算出使用k次魔力之后魔力手环的状态。 

输入描述:
输入数据包括两行:
第一行为两个整数n(2 ≤ n ≤ 50)和k(1 ≤ k ≤ 2000000000),以空格分隔
第二行为魔力手环初始的n个数,以空格分隔。范围都在0至99.


输出描述:
输出魔力手环使用k次之后的状态,以空格分隔,行末无空格。

输入例子:
3 2
1 2 3

输出例子:
8 9 7
思路:矩阵快速幂

http://huang22.top/2016/04/11/%E7%9F%A9%E9%98%B5%E5%BF%AB%E9%80%9F%E5%B9%82/

public class Main {
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()) {
			int n = sc.nextInt(), m = sc.nextInt();
			int[]a=new int[n];
			for(int i=0; i<n; i++)a[i]=sc.nextInt();
			
			int[][] matrix = new int[n][n];
			for(int i=0; i<n; i++) {
				matrix[i][i]=1;
				matrix[(i+1)%n][i]=1;
			}
			
			int[][] pow = matrixPower(matrix, m);
			int[] rst = helper(a, pow);
			for(int i=0; i<rst.length-1; i++)
				System.out.print(rst[i]+" ");
			System.out.println(rst[n-1]);
		}
	}
	
	
	public static int[][] matrixPower(int[][] a, int n) {
		// 注意:初始化为单位矩阵
		int[][] b = new int[a.length][a.length];
		for(int i=0; i<a.length; i++)
			b[i][i] = 1;
		
		while(n != 0) {
			if((n & 1) != 0)
				b = helper(b, a);
			n = n >> 1;
			a = helper(a, a);
		}
		return b;
	}
	
	public static int[][] helper(int[][] a, int[][] b) {
		// 写的是方阵相乘的结果
		int[][] c = new int[a.length][a.length];
		for(int i=0; i<a.length; i++)
			for(int j=0; j<a.length; j++) {
				for(int k=0; k<a.length; k++)
					c[i][j] += a[i][k] * b[k][j];
				c[i][j] %= 100;
			}
		return c;
	}
	
	public static int[] helper(int[] a, int[][] b) {
		int[] c = new int[a.length];
		for(int i=0; i<a.length; i++) {
			for(int k=0; k<a.length; k++)
				c[i] += a[k] * b[k][i];
			c[i] %= 100;
		}
		return c;
	}

}









小易有n块砖块,每一块砖块有一个高度。小易希望利用这些砖块堆砌两座相同高度的塔。为了让问题简单,砖块堆砌就是简单的高度相加,某一块砖只能使用在一座塔中一次。小易现在让能够堆砌出来的两座塔的高度尽量高,小易能否完成呢。 
输入描述:
输入包括两行:
第一行为整数n(1 ≤ n ≤ 50),即一共有n块砖块
第二行为n个整数,表示每一块砖块的高度height[i] (1 ≤ height[i] ≤ 500000)


输出描述:
如果小易能堆砌出两座高度相同的塔,输出最高能拼凑的高度,如果不能则输出-1.
保证答案不大于500000。

输入例子:
3
2 3 5

输出例子:
5


思路:这道题真是惭愧,看了好几天别人的DP代码还是看不懂,后来用Java写DFS+剪枝,虽然想出了很多稀奇古怪的剪枝策略,但是无奈Java太慢了,只能AC 90%,可见DFS这种方法用来做这样的题还是很勉强

DP以后看懂了再更新吧。。。。

package l10;

import java.util.*;
/*
 * DFS + 剪枝
 * 但是Java是不行的
 */
public class Copy_4_of_Main {
	
	static int rst = 0;
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()) {
			int n = sc.nextInt();
			int[]cost = new int[1+n];
			for(int i=1; i<=n; i++)
				cost[i]=sc.nextInt();
			
			Arrays.sort(cost);
			int[] tmp = new int[1+n];
			for(int i=1; i<=n; i++)
				tmp[i] = cost[n-i+1];
			cost = tmp;
			
			int[] rightSum = new int[1+n];
			rightSum[n] = cost[n];
			for(int i=n-1; i>=1; i--)
				rightSum[i] = rightSum[i+1] + cost[i];
			
			rst = 0;
			dfs(cost, rightSum, 1, 0, 0);
			System.out.println(rst == 0 ? -1 : rst);
		}
	}

	private static void dfs(int[] cost, int[] rightSum, int cnt, int left, int right) {
		if(left == right)		rst = Math.max(rst, left);
		if(cnt == cost.length)	return;
		if((left + right + rightSum[cnt]) / 2 <= rst)	return;
		if(left + rightSum[cnt] < right || right + rightSum[cnt] < left)	return;
		
		dfs(cost, rightSum, 1+cnt, left+cost[cnt], right);
		dfs(cost, rightSum, 1+cnt, left, right+cost[cnt]);
		dfs(cost, rightSum, 1+cnt, left, right);
	}


}





易老师购买了一盒饼干,盒子中一共有k块饼干,但是数字k有些数位变得模糊了,看不清楚数字具体是多少了。易老师需要你帮忙把这k块饼干平分给n个小朋友,易老师保证这盒饼干能平分给n个小朋友。现在你需要计算出k有多少种可能的数值 
输入描述:
输入包括两行:

第一行为盒子上的数值k,模糊的数位用X表示,长度小于18(可能有多个模糊的数位)

第二行为小朋友的人数n


输出描述:
输出k可能的数值种数,保证至少为1

输入例子:
9999999999999X
3

输出例子:
4

思路:DFS会TLE,因为后面的结果也前面是相关联的:到当前位为止的余数与前一位的余数个数是由关系的
就是把前面计算过的结果用起来
package l11;
import java.util.*;

/*
 * 到当前位为止的余数与前一位的余数个数是由关系的
 * 所以考虑用DP
 */
public class Main {
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()) {
			String s = sc.next();
			String sr = new StringBuilder(s).reverse().toString();
			int n = sc.nextInt();
			
			//dp[i][j]表示到index为i的时候,余数为j的个数
			long[][] dp = new long[sr.length()+1][n];
			dp[0][0] = 1;
			int base = 1;
			for(int i=1; i<=sr.length(); i++) {
				if('X' == sr.charAt(i-1)) {
					for(int j=0; j<10; j++) {
						for(int k=0; k<n; k++) {
							int newLeft = (k + j * base) % n;
							dp[i][newLeft] += dp[i-1][k];
						}
					}
				} else {
					int j = sr.charAt(i-1) - '0';
					for(int k=0; k<n; k++) {
						int newLeft = (k + j * base) % n;
						dp[i][newLeft] += dp[i-1][k];
					}
				}
				
				base *= 10;
				base %= n;
			}
			
			System.out.println(dp[sr.length()][0]);
		}
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值