算法练习之数学问题

题目:巧用进制,天平称重

用天平称重时,我们希望用尽可能少的砝码组和出尽可能多的重量。如果有无限个砝码,但他们的重量分别是1,3,9,27,81,······等3的指数幂。神奇之处在于用他们的组和可以称出任意整数重量(砝码允许放在左右两个盘子中)。

本题目要求编程实现:对用户给定的重量,给出砝码组和方案,重量<100000.

例如:用户输如:5

程序输出: 9 -3-1

解题思路:

利用进制来解。

因为1,3, 9······都是3的幂,所以用3进制来解。

例如:

5转化为3进制为 12 
答案为       9 -3 -1
对应三进制为  1  -1  -1
    
因为每个砝码只能用一次。所以将12 进位
 2 进位需要加1,所有进位在该为再减1,即 12 变为 2-12继续进位可变为:  1-1-1
 
 此时对应的数正好可转为:1 * 3^2, -1 * 3^1 ,-1 * 3^0
 		即对应: 9 -3 -1 正好为答案。

java代码示例:

import java.util.ArrayList;
import java.util.Scanner;

public class 天平称重 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		//转成三进制
		final String x = Integer.toString(n, 3);
		//翻转后转为数组
		char[] arr = new StringBuffer(x).reverse().toString().toCharArray();
		// 用来存取处理之后的0, 1 -1
		ArrayList<Integer> list = new ArrayList<Integer>();
		for(int i = 0; i < arr.length; i++) {
			if(arr[i] == '2') {
				list.add(0, -1);//-1插在开头
				if(i == arr.length - 1) {
					list.add(0, 1);
				}else {
					arr[i+1] += 1;
				}
			}else if(arr[i] == '3') {
				list.add(0, 0);
				//更高为进1
				if(i == arr.length - 1) {
					list.add(0, 1);
				}else {
					arr[i+1] += 1;
				}
			}else {
				list.add(0, arr[i] - '0');
			}
		}
		StringBuilder sb = new StringBuilder();
		for(int i = 0; i < list.size(); i++) {
			if(list.get(i) == 1) {
				sb.append("+").append((int)Math.pow(3, list.size() - i - 1));
			}
			if(list.get(i) == -1) {
				sb.append("-").append((int)Math.pow(3, list.size() - i - 1));
			}
		}
		System.out.println(sb.substring(1));
		
	}
}

程序运行结果:

5
9-3-1

题目:Nim游戏

一共有N堆石子,编号1-n ,第i堆中有a[i]个石子。每一次操作Alice和Bob可以从任意一堆石子中取出任意数量的石子,至少取一颗,至多取出这一堆剩下的所有石子。

两人轮流行动,取光所有石子的一方获胜。Alice为先手。

给定a,假设两人都采取最优策略,谁会获胜。

解题思路:

利用二进制异或。

解题示例:

假设有三队 345 
变为二进制位   3     0  1  1
     		 4		1  0  0
    异或	    5	   1  0  1
    --------------------------
    				0   1  0
每次当轮到自己时异或结果为0,对手采取最优策略则自己输。
如果轮到自己时,异或结果非0,则自己必胜。

每次拿取石子策略,留给对手的异或结果为0,则必胜

java代码示例:

public class Nim游戏 {
	public static void main(String[] args) {
		int[] A	= {3, 4, 5};
		boolean res = solve(A);
		System.out.println(res);
		int[] B	= {7, 9, 8};
		res = solve(B);
		System.out.println(res);
	}
	
	public static boolean solve(int[] A) {
		int res = 0;
		for(int i = 0; i < A.length; i++) {
			res ^= A[i];
		}
		return res != 0;
	}
}

程序运行结果:

true
true

题目:识别Nim问题,Georgia and Bob

Georgia和Bob决定玩一个自己发明的游戏。他们在纸上画一排网格,从左到右给网格编号1、2、3、…,放置N个棋子或不同网格,如下图所示:

在这里插入图片描述

Georgia和Bob轮流移动棋子。每次玩家将选择一个棋子,并将其移动到左边,而不越过任何其他棋子或他的左边缘。掠夺者可以自由选择棋子移动的步数,约束条件是棋子必须移动至少一步,一个网格最多只能包含一个棋子。不会走一步棋的菜鸟输了这场比赛。

自从“女士优先”以来,Georgia总是第一个上场。假设Georgia和Bob都在游戏中表现最好,即如果他们中的一个人知道赢得比赛的方法,他或她就能实现它。即使是n个棋子的初始位置,你能预测出最终谁会赢吗

输入:

输入的第一行包含单个整数T (1 <= T <= 20),即测试用例的数量。然后T个例子。每个测试用例包含两行。第一行包含一个整数N (1 <=N <= 1000),表示棋子的数量。第二行包含N个不同的整数P1 P2。。Pn (1 <= Pi <= 10000),是n个棋子的初始位置。

输出:

输出对于每个测试用例,打印一行“Georgia will win”,如果Georgia愿意参与游戏;“Bob will win”,如果Bob会赢的话;否则“Not sure”

示例输入:

2
3
1 2 3
8
1 5 6 7 9 12 14 17

示例输出:

Bob will win
Georgia will win

解题思想:

首先要识别出这是一个Nim问题。

以两个一组作为一堆。

java代码示例:

import java.util.Arrays;
import java.util.Scanner;
/**
 * 输入:
 * 2
 * 3
 * 1 2 3
 * 8
 * 1 5 6 7 9 12 14 17
 *输出:
 * Bob will win
 * Georgia will win
 */
public class 阶梯Nim问题 {

	public static void main(String[] args) {
		Scanner sc  =  new Scanner(System.in);
		int caseNum = sc.nextInt();
		int[][] data = new int[caseNum][];
		for(int i = 0; i < caseNum; i++) {
			int k = sc.nextInt();
			data[i] = new int[k];
			for(int j = 0; j < k; j++) {
				data[i][j] = sc.nextInt();
			}
		}
		for(int i = 0; i < caseNum; i++) {
			String res = deal(data[i]);
			System.out.println(res);
		}
	}

	private static String deal(int[] A) {
		int len = A.length;
		Arrays.sort(A);
		int res = 0;
		if((len & 1) == 1) { //奇数
			for(int i = 0; i < len; i+=2) {
				if(i == 0) {
					res ^=  (A[0]-1);
				}else {
					res ^= (A[i] - A[i-1] -1);
				}
			}
		}else {
			for(int i = 1; i < len; i+=2) {
				res ^= (A[i] - A[i-1] -1);
			}
		}
		if(res == 0) {
			return "Bob will win";
		}else {
			return "Georgina will win";
		}
	}

}

程序运行结果:

2
3
1 2 3
8
1 5 6 7 9 12 14 17
Bob will win
Georgina will win

欧几里得算法

public class 欧几里得算法 {
	public static void main(String[] args) {
		System.out.println(gcd(18, 12));
	}
	
	public static int gcd(int m, int n) {
		return n == 0 ? m : gcd(n, m % n);
	}
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页