Round A APAC Test 2017 java完整代码及解答

第一题:country leader

package googleJam;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;

public class CountryLeader {
	
	ArrayList<Character> list = new ArrayList<>();
	
	public CountryLeader(Scanner in) {
		
			int T = in.nextInt();
			for(int t=1;t<=T;t++){
				int result=0;
				int index=0;//每次循环都要重新赋初值,那么就应该放在循环的开头
				int n = in.nextInt();
				String[] names = new String[n];
				String dele = in.nextLine();
				for(int i=0;i<n;i++){
					
					names[i] = in.nextLine();//人名放在数组里
					if(differLetter(names[i])>result){
						index = i;
						result = differLetter(names[index]);
					}else if(differLetter(names[i])==result){
						if(names[i].compareTo(names[index])<0){
							index = i;
							result = differLetter(names[index]);
						}
						
					}
				}
				System.out.println("Case #"+t+": "+names[index]);
			}
		
		
	}
	public static void main(String[] args) throws Exception{
		// TODO 自动生成的方法存根
		
		String filename = "A-large-practice.in";
		System.setIn(new FileInputStream(filename));	
		System.setOut(new PrintStream(new FileOutputStream("A-large-practice-out.txt")));
		Scanner in = new Scanner(System.in);
		CountryLeader ex = new CountryLeader(in);
		in.close();

	}
	public int differLetter(String str){
		int count = 0;
		for(int i=0;i<str.length();i++){
			if(!list.contains(str.charAt(i)) && (str.charAt(i)!=' ')){
				list.add(str.charAt(i));//使用了26个额外的空间复杂度,但是常数级空间算O(1)还是O(N)
				count++;
			}
		}
		list.clear();
		return count;
	}

}

第二题:rain

package googleJam;

import googleJam.Rain2.Cell;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;
//这道题循环遍历不是有网格来决定,而是由优先队列里的队首元素决定,每一个节点都可以先当做边界,不找低地,找最短边界储水
/*
 * @author Mingfang.z 在别人基础上自己修改的代码
 * 思路:先将边界装入优先队列中(高度越小越优先),并标记为已访问。看队首元素四周未访问过的点,
 * 1、如果该点不比队首低,则将它加入队列,标记为已访问,即它变成了新的边界。
 * 2、该点比队首低,意味着该点可以储水,更新res值,同时将它加入队列中,但是它的高度为原队首元素的高度,即以它为边界的点不能超过这个高度,
 * 同时将该点标记为已访问。
 */
public class Rain {

	/**
	 * @param args
	 */
	public Rain(Scanner in){
		
		PriorityQueue<Grid> queue = new PriorityQueue<>(11,new Comparator<Grid>() {
			public int compare(Grid grid1, Grid grid2){
				return grid1.h - grid2.h;
			}				
		});//接口实现具体方法大括号后面要加分号
		int T = in.nextInt();
		for(int t=1;t<=T;t++){
			int r = in.nextInt();
			int c = in.nextInt();
			int[][] h = new int[r][c];
			for(int i=0;i<r;i++){
				for(int j=0;j<c;j++){
					h[i][j] = in.nextInt();//输入的原网格
					if(i==0||i==r-1||j==0||j==c-1){
						queue.add(new Grid(i, j, h[i][j]));//加入外围四条边,队列初始化
					}
				}
			}
			boolean[][] visited = new boolean[r][c];
			int wCount = 0;//记录储水值
			while(!queue.isEmpty()){
				Grid grid = queue.poll();
				visited[grid.i][grid.j] = true;
				wCount += waterCount(h, visited, grid.i+1, grid.j, grid.h, queue);
				wCount += waterCount(h, visited, grid.i-1, grid.j, grid.h, queue);
				wCount += waterCount(h, visited, grid.i, grid.j-1, grid.h, queue);
				wCount += waterCount(h, visited, grid.i, grid.j+1, grid.h, queue);
			}
			System.out.println("Case #"+t+": "+wCount);								
		}
	}
		/*对每一个优先队列里的最小边界节点计算周围储水值
		 * @param
		 * curH是队首最小边界
		 * h[i][j]是四周遍历的节点
		 */
	public int waterCount(int[][] h, boolean[][] vis, int i, int j, int curH, PriorityQueue<Grid> queue ){
		if(i<0||i>=h.length||j<0||j>=h[0].length||vis[i][j]) return 0;
		else{
			vis[i][j] = true;//判断该节点是否被访问
			//curH = queue.poll().h;
			queue.add(new Grid(i, j, Math.max(curH, h[i][j])));
			return Math.max(0, curH-h[i][j]);
			}
		}
	class Grid{//每一个网格的参数需要储存i,j,h
		int i, j, h;
		public Grid(int i, int j, int h){
			this.i = i;//参数赋值给全局变量,实例变量是对象调用的需要this关键词
			this.j = j;
			this.h = h;
		}
	}
	public static void main(String[] args) throws IOException {
		// TODO 自动生成的方法存根
		String filename = "B-small-practice.in";
		System.setIn(new FileInputStream(filename));	
		System.setOut(new PrintStream(new FileOutputStream("B-small-practice-out.txt")));		
		Scanner in = new Scanner(System.in);
		new Rain(in);
		in.close();
		System.exit(0);
	}	
}

第三题:jane's flower shop

花店这道题核心是理解题中给出的公式,找到公式规律。题中给出花店开了M月,和每个月的收入,以及刚开始的总成本,我们可以用一个int c[m+1]来储存,c[0]为总成本cost,其余为相对应每月的收入,这样有点好处就是,c[i]就是第i月的收入,索引不用减一。

然后写函数方程。很容易找到规律,题中方程为 -c[0]*(1+r)^m+c[1]*(1+r)^(m-1)+````+c[m-1]*(1+r)^1+c[m]*(1+r)^0 = 0;可以看出除了开头的cost部分,每月的收入都是c[i]*(1+r)^(m-i),所以我们在计算函数值得时候,循环变量即为c数组的索引i,从1到m。注意,由于r的精度很高,所以此时必须使用大数计算BigDecimal函数,就是说每一次加减乘除都要先new BigDecimal对象,再用它的实例方法add() multiply(),最后r的结果应该是double型,所以在查找r取值的时候,要以double型。

代码中的compute函数就是计算当IRR = r的时候根据方程所得函数值,返回的是一个bigdecimal的对象,其实我觉得也可以返回double或int型,提前判断是大于0还是小于0,单我看别人是用bigdecimal.compare去比较,所以也这么写了,可能精确一点吧,毕竟前面都是用它来计算。

然后是本题的核心部分,二分查找。拿到函数和自变量区间,我们首先应该去考虑它的特性(单调性,最值等),因为本题只有唯一解,所以图像与x轴只有一个交点,且F(-1)>0 因为方程末尾有常数项,所以得出函数单调递减。这样我们再二分查找的时候,当取得r值带进去算的函数值大于0,我们就知道要向右边移动,所以left =middle+0.000000000001,否则就是high = middle-0.000000000001。因为在二分查找的原型中,是用while(l<=r)来控制循环的,所以我们这里也可以借鉴过来,但是要想到,此时的left和right都是精确到小数点后12位的double型(根据题中给的测试用例可以得到),所以无法精确地比较两者大小,所以我们只需要控制他们的精度到小数点后12位就行了,其他的不用管,所以就是while(high-low>=0.000000000001)而当high和low在12位处相等时,我们选择显示两者中的任何一个当做r都可。

package googleJam;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.math.BigDecimal;
import java.util.Scanner;
//此题不仅求解方程,对结果的精确度要求高,大数运算,因为small数据只是一次和二次方程,易求,可以先算出来
//java的输出数据格式要规定,format,数据输出精度只能大不能减,double>float
public class JaneFlowerShop {

	/**
	 * @param args
	 */
	JaneFlowerShop(Scanner in){
		while(in.hasNext()){
			int T = in.nextInt();
			for(int t = 1;t<=T;t++){
				int m = in.nextInt();
				long[] c = new long[m+1];
				for(int i=0;i<=m;i++){
					c[i] = in.nextLong();
				}
				System.out.println(String.format("Case #%d: %.12f", t,irr(c,m)));//格式化输出,保留double数据小数点后12位
			}
		}
	}
	//计算参数r的函数值
	public BigDecimal compute(long[] c,int m,double r){
		BigDecimal r1 = new BigDecimal(1+r);
		BigDecimal res = new BigDecimal(c[0]).multiply(r1.pow(m)).negate();//初值,用的是bigdecimal的pow不是math的pow
		for(int i=1;i<=m;i++){
			res = res.add(new BigDecimal(c[i]).multiply(r1.pow(m-i)));
		}
		return res;
	}
	
	//二分查找r在区间(-1,1)中,先用非递归,返回r
	public double irr(long[] c,int m){
		double low = -1;
		double high = 1;	
		while(high - low>=0.000000000001){//这只是控制了小数点后12位的精度,但如果high,low并不相等,到达小数点后13位且方程值仍不为0的话,就会跳出循环
			double middle = (low+high)/2;//>>1只有int型有
			BigDecimal value = compute(c,m,middle);
			if(value.compareTo(new BigDecimal(0.0))==0) return middle;//Double.valueOf(double d)是double的包装类,将基本类型转换为类的对象
			else if(value.compareTo(new BigDecimal(0.0))>0){
				low = middle + 0.000000000001;//因为在区间里,函数值value是逆序的
			}else if(value.compareTo(new BigDecimal(0.0))<0){
				high = middle - 0.000000000001;
			}			
		}
		return low;//所以为了在控制的精度内返回r值,就当做当high和low相差小于1e-12时,当做两者相等,查找结束,
	}
	
	public static void main(String[] args) throws IOException {
		// TODO 自动生成的方法存根
		String filename = "C-small-practice.in";
		System.setIn(new FileInputStream(filename));	
		System.setOut(new PrintStream(new FileOutputStream("C-small-practice-out.txt")));		
		Scanner in = new Scanner(System.in);
		new JaneFlowerShop(in);
		in.close();

	}

}

第四题:clash royale

这道题题意是:部落冲突是一款即时策略的卡牌游戏,现在需要制定一种策略,使得每次小家伙拿出的8张牌的总攻击力是最大的,在不超过自己拥有金币的前提下。

思路是借鉴别人的,才敢用暴力,当时在写的时候想到如果穷举,要写八个循环,吓怕了,后来看别人才知道其实还是能过的。

把八张卡牌分两次计算,前四张暴力穷举用list储存每一种组合所消耗的coins和产生的power,后四张同理。有说可以利用排序来删除无效数据,刚开始我想着也用优先队列来排,但是后来还要考虑筛选有效数据,就放弃了,因为毕竟我都已经用八个循环做了,不在乎这点了。

计算过程中需要加上一个条件,就是当四张牌消耗的coins总和超过了总的金币M,那这种组合就不用add了。

编写的时候,我们需要找到循环变量,因为这道题解答的是一种组合方案,而决定我每张牌不同组合的是它的level,也就是每张牌升级不同(等级不同),导致最后打别人的总攻击力不同。所以,计算时,我们的循环变量应该是每张牌的level,从L到K

下面只实现了small,别人的small都很短,我的写的太长,是奔着large去的,惭愧

代码中用了几个类来包装每张卡牌的coins和power,相比于用二维数组,觉得清晰一点

package googleJam;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Scanner;
//这道题分两次暴力枚举,前四张牌和后四张牌,本来筛选后排序,可以删除掉无效数据,但是不会删,所以没有用queue
//large的话,同样枚举,c(12,8)很小不影响,每次从12张中选出8张牌,计算每8张牌的resA power值并取最大(没写)
public class ClashRoyale {

	/**
	 * @param args
	 */
	//每一种方案的排序规则:coins从小到大排,当coins相同时,power从大到小排,都相同时无论先后(没有用到)
	PriorityQueue<Item> queue = new PriorityQueue<>(11,new Comparator<Item>() {
		public int compare(Item item1, Item item2){
			if(item1.coins<item2.coins) 
				return -1;
			else if(item1.coins>item2.coins)
				return 1;
			else{
				if(item1.power>item2.power)
					return -1;
				else if(item1.power<item2.power)
					return 1;
				else return 0;
			}
		}				
	});//接口实现具体方法大括号后面要加分号
	
	List<Item> group1 = new ArrayList<>();
	List<Item> group2 = new ArrayList<>();//前后四张牌的每种组合
	ClashRoyale(Scanner in){
		int T = in.nextInt();
		for(int t=1;t<=T;t++){
			int M = in.nextInt();
			int N = in.nextInt();
			long resA = 0;//储存最大power,每张牌最大power10^10,所以总的最大是8*10^10,为long型
			//int resC = 0;//储存消耗coins
			List<Cards> list = new ArrayList<Cards>(8);//cards
			for(int i=0;i<N;i++){
				int k = in.nextInt();
				int l = in.nextInt();
				int[] a = new int[k];
				int[] c = new int[k-1];
				for(int j=0;j<k;j++){
					a[j] = in.nextInt();
				}
				for(int z=0;z<k-1;z++){
					c[z] = in.nextInt();
				}
				list.add(new Cards(k, l, a, c));
			}
			//前四张牌的穷举,计算coins和power
			int coinsi = 0;int coinsj = 0;int coinsm = 0;int coinsn = 0;
			for(int i=list.get(0).l;i<=list.get(0).k;i++){//用level变量循环
				if(i==list.get(0).l) coinsi = 0;
				else coinsi += list.get(0).c[i-2];
				/*
				for(int ii=0;ii<i-1;ii++){
					coinsi += list.get(0).c[ii];
				}*/
				for(int j=list.get(1).l;j<=list.get(1).k;j++){
					if(j==list.get(1).l) coinsj = 0;
					else coinsj += list.get(1).c[j-2];
					
					for(int m=list.get(2).l;m<=list.get(2).k;m++){
						if(m==list.get(2).l) coinsm = 0;
						else coinsm += list.get(2).c[m-2];
						
						for(int n=list.get(3).l;n<=list.get(3).k;n++){
							if(n==list.get(3).l) coinsn = 0;
							else coinsn += list.get(3).c[n-2];
							
							if(coinsi+coinsj+coinsm+coinsn<=M)
								//queue.add(new Item(coinsi+coinsj+coinsm+coinsn, list.get(3).a[n-1]+list.get(2).a[m-1]+
								//	list.get(1).a[j-1]+list.get(0).a[i-1]));
								group1.add(new Item(coinsi+coinsj+coinsm+coinsn, list.get(3).a[n-1]+list.get(2).a[m-1]+
										list.get(1).a[j-1]+list.get(0).a[i-1]));
						}
					}
				}
			}
			//后四张牌计算
			int coinsi2 = 0;int coinsj2 = 0;int coinsm2 = 0;int coinsn2 = 0;
			for(int i2=list.get(4).l;i2<=list.get(4).k;i2++){
				if(i2==list.get(4).l) coinsi2 = 0;
				else coinsi2 += list.get(4).c[i2-2];
				
				for(int j2=list.get(5).l;j2<=list.get(5).k;j2++){
					if(j2==list.get(5).l) coinsj2 = 0;
					else coinsj2 += list.get(5).c[j2-2];
					
					for(int m2=list.get(6).l;m2<=list.get(6).k;m2++){
						if(m2==list.get(6).l) coinsm2 = 0;
						else coinsm2 += list.get(6).c[m2-2];
						
						for(int n2=list.get(7).l;n2<=list.get(7).k;n2++){
							if(n2==list.get(7).l) coinsn2 = 0;
							else coinsn2 += list.get(7).c[n2-2];
							
							if(coinsi2+coinsj2+coinsm2+coinsn2<=M)
							//queue2.add(new Item(coinsi2+coinsj2+coinsm2+coinsn2, list.get(7).a[n2-1]+list.get(6).a[m2-1]+
							//			list.get(5).a[j2-1]+list.get(4).a[i2-1]));
							group2.add(new Item(coinsi2+coinsj2+coinsm2+coinsn2, list.get(7).a[n2-1]+list.get(6).a[m2-1]+
									list.get(5).a[j2-1]+list.get(4).a[i2-1]));
						}
					}
				}
			}
			//更新resA求最大power(暴力枚举,先不排序了)
			for(int z =0;z<group1.size(); z++){
				for(int y=0;y<group2.size(); y++){
					Item it1 = group1.get(z);
					Item it2 = group2.get(y);
					if(it1.coins+it2.coins<=M){
						resA = Math.max(resA, it1.power+it2.power);
					}
				}			
			}		
			System.out.println("Case #"+t+": " + resA);
			group1.clear();
			group2.clear();
			
		}
	}
	
	public static void main(String[] args) throws IOException {
		// TODO 自动生成的方法存根
		String filename = "D-small-practice.in";
		System.setIn(new FileInputStream(filename));	
		System.setOut(new PrintStream(new FileOutputStream("D-small-practice-out.txt")));		
		Scanner in = new Scanner(System.in);
		new ClashRoyale(in);
		in.close();
	}
	// i-th cards param
	class Cards{
		int k,l;
		int[] a = new int[k];// each level power
		int[] c = new int[k-l];//upgrading each level coins
		Cards(int k,int l,int[] a,int[] c){
			this.k = k;
			this.l = l;
			this.a = a;
			this.c = c;
		}
		
	}
	class Item{
		int coins;
		int power;
		Item(int coins,int power){
			this.coins = coins;
			this.power = power;
		}
	}
}

剩下的稍后写

如果有好的解答,欢迎分享

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值