【编程马拉松】【011-鸽兔同校】
来源:互联网 发布:泰国4g网络制式 频段 编辑:程序博客网 时间:2024/05/01 23:07
【编程马拉松算法目录>>>】
【011-鸽兔同校】【工程下载>>>】
1 题目描述
浙江大学校园里绿树成荫,环境非常舒适,因此也引来一批动物朋友来此居住。
童心未泯的NowCoder就经常带些碎面包什么的去广场喂鸽子和兔子,并和它们玩耍。 一点也没有大学生的样子,还是一副老不正经的样子,呵呵。
随着鸽子和兔子数目的增多,NowCoder带的那点食物已经不够它们瓜分了。为了能让自己的好朋友吃的饱饱的, NowCoder决定统计一下有多少只鸽子和有多少只兔子,以便带来足够的食物。一、二、三、四、五…他开始数了。
现在,他已经知道有这些鸽子和兔子一共有n个头和m只脚。请你帮他写个程序计算一下一共有多少只鸽子和兔子。
1.1 输入描述:
输入包括多组数据。
每行包括2个正整数n和m,n和m可能会很大,超过2^64,但位数不超过100位。
1.2 输出描述:
每组数据的输出都只有一行,分别是鸽子的数量和兔子数量。
如果输入的测试数据不能求得结果,那肯定是NowCoder这个马大哈数错了,就输出“Error”提示他。
1.3 输入例子:
35 941 3
1.4 输出例子:
23 12Error
2 解题思路
假设有x只鸽子,y只兔子,它们的头和脚的数目分别是m和n。则有:
{x+y=m2x+4y=n⟺{x=4m−n2y=n−2m2x∈Ny∈N
x和y都是自然数⇒n为偶数,
3 算法实现
import java.util.Scanner;/** * Author: 王俊超 * Time: 2016-05-09 13:55 * CSDN: http://blog.csdn.net/derrantcm * Github: https://github.com/Wang-Jun-Chao * Declaration: All Rights Reserved !!! */public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in);// Scanner scanner = new Scanner(Main.class.getClassLoader().getResourceAsStream("data.txt")); while (scanner.hasNext()) { String m = scanner.next(); String n = scanner.next(); String[] r = pigeonAndRabbit(m, n); if (r == null) { System.out.println("Error"); } else { System.out.println(r[0] + " " + r[1]); } } scanner.close(); } /** * 计算鸽子和兔子的数目 * * @param ms 鸽子和兔子的头数 * @param ns 鸽子和兔子的脚数 * @return 长度为2的数符串,分别表示鸽子的数量和兔子数量,如果无解就返回null */ private static String[] pigeonAndRabbit(String ms, String ns) { int lastN = ns.charAt(ns.length() - 1) - '0'; // ns为偶数 if (lastN % 2 != 0) { return null; } int[] m = getNumber(ms); int[] n = getNumber(ns); // 鸽子数 // 4 * m int[] x = multiply(m, new int[]{4}); // 兔子数 // 2 * m int[] y = multiply(m, new int[]{2}); // 4m >= n && n >= 2m if (compare(x, n) >= 0 && compare(n, y) >= 0) { // 4m - n x = minus(x, n); // (4m - n) / 2 x = divide2(x); // n - 2m y = minus(n, y); // (n - 2m) / 2 y = divide2(y); return new String[]{toNumber(x), toNumber(y)}; } else { return null; } } /** * 将整数字符串表示成整数数组 * * @param n 整数字符串 * @return 整数数组 下标从小到大表示数位的从低到高 */ private static int[] getNumber(String n) { int[] r = new int[n.length()]; for (int i = 0; i < r.length; i++) { r[i] = n.charAt(n.length() - i - 1) - '0'; } return r; } /** * 两个数相乘 * * @param m 乘数 * @param n 乘数 * @return 结果 */ private static int[] multiply(int[] m, int[] n) { // 结果最多的位数 int[] r = new int[m.length + n.length]; // 来自低位的进位 int c; int t; int k; for (int i = 0; i < n.length; i++) { // 计算n[i]*m if (n[i] == 0) { continue; } c = 0; for (int j = 0; j < m.length; j++) { t = n[i] * m[j] + r[i + j] + c; r[i + j] = t % 10; c = t / 10; } // 如果还有进位要继续处理 k = i + m.length; while (c != 0) { t = c + r[k]; r[k] = t % 10; c = t / 10; k++; } } return r; } /** * 两个整数相加 * * @param m 整数 * @param n 整数 * @return 结果 */ private static int[] add(int[] m, int[] n) { // 保证n不小于m if (m.length > n.length) { int[] t = m; m = n; n = t; } // 结果的最大长度 int[] r = new int[n.length + 1]; // 来自低位的进位 int c = 0; for (int i = 0; i < m.length; i++) { r[i] = m[i] + n[i] + c; c = r[i] / 10; r[i] %= 10; } // 计算余下的部分 for (int i = m.length; i < n.length; i++) { r[i] = n[i] + c; c = r[i] / 10; r[i] %= 10; } // 最后还有进位 if (c != 0) { r[r.length - 1] = c; return r; } // 没有进位 else { int[] ret = new int[r.length - 1]; System.arraycopy(r, 0, ret, 0, ret.length); return ret; } } /** * 比较两个整数是否相等,下标由小到大表示由低位到高位,忽略最高有效位上的前导0 * * @param m 整数 * @param n 整数 * @return m > n返回1,m = n返回0,m < n返回-1 */ private static int compare(int[] m, int[] n) { if (m == null && n == null) { return 0; } // null最小 if (m == null) { return -1; } if (n == null) { return 1; } int lastM = m.length - 1; int lastN = n.length - 1; // 找m的最高有效位的位置,至少有一位 while (lastM >= 1 && m[lastM] == 0) { lastM--; } // 找n的最高有效位的位置,至少有一位 while (lastN >= 1 && n[lastN] == 0) { lastN--; } // m的数位比n多,说明m比n大 if (lastM > lastN) { return 1; } // m的数位比n少,说明m比n小 else if (lastM < lastN) { return -1; } else { // 位数一样,比较每一个数位上的值,从高位到低位进行比较 for (int i = lastM; i >= 0; i--) { if (m[i] > n[i]) { return 1; } else if (m[i] < n[i]) { return -1; } } return 0; } } /** * 做减法n-m,保证n大于等于m * * @param n 整数 * @param m 整数 * @return 结果 */ private static int[] minus(int[] n, int[] m) { n = format(n); m = format(m); int[] r = new int[n.length]; // 当前位被借位 int c = 0; int t; for (int i = 0; i < m.length; i++) { t = n[i] - c - m[i]; // 当前位够减 if (t >= 0) { r[i] = t; // 没有进行借位 c = 0; } // 不够减 else { r[i] = t + 10; // 进行借位 c = 1; } } // 还有借位 for (int i = m.length; c != 0 && i < n.length; i++) { t = n[i] - c; // 当前位够减 if (t >= 0) { r[i] = t; // 没有进行借位 c = 0; } // 不够减 else { r[i] = t + 10; // 进行借位 c = 1; } } return format(r); } /** * 将整数进行格式化,去掉高位的前导0 * * @param r 整数 * @return 结果 */ private static int[] format(int[] r) { int t = r.length - 1; // 找最高有效位 while (t > 0 && r[t] == 0) { t--; } int[] nr = new int[t + 1]; System.arraycopy(r, 0, nr, 0, nr.length); return nr; } /** * 将数n除以2 * * @param n 整数 * @return 结果 */ private static int[] divide2(int[] n) { // 结果 int[] r = new int[n.length]; // 上一位除以2后的余数 int c = 0; int t; for (int i = n.length - 1; i >= 0; i--) { t = c * 10 + n[i]; r[i] = t / 2; c = t % 2; } return format(r); } /** * 将数组表示的整数转换成字符串 * * @param r 整数 * @return 字符串表示的整数 */ private static String toNumber(int[] r) { if (r == null) { return null; } StringBuilder b = new StringBuilder(r.length); for (int i = r.length - 1; i >= 0; i--) { b.append(r[i]); } return b.toString(); }}
4 测试结果
5 其它信息
因为markddow不好编辑,因此将文档的图片上传以供阅读。Pdf和Word文档可以在Github上进行【下载>>>】。
2 0
- 【编程马拉松】【011-鸽兔同校】
- 鸽兔同校
- 编程马拉松总结
- 换零钱---编程马拉松
- 鹊桥相会---编程马拉松
- 编程马拉松:电话号码
- 【编程马拉松算法目录】
- 【编程马拉松】【012-Hero】
- 编程马拉松17C
- 我的编程马拉松
- 人工智能编程马拉松
- 编程马拉松----走迷宫
- 2013腾讯编程马拉松初赛
- 【编程马拉松】【001-NowCoder猜想】
- 【编程马拉松】【002-分遗产】
- 【编程马拉松】【003-素数和】
- 【编程马拉松】【004-包含一】
- 【编程马拉松】【006-统计一】
- JAVA初始化
- 面向接口编程详解——思想基础
- android中常用的属性
- Machine Leanring-Principal Component Analysis(PCA)
- BZOJ4592 [Shoi2015]脑洞治疗仪
- 【编程马拉松】【011-鸽兔同校】
- ubuntu12.04中的ibus汉语怎么用
- 二分图匹配相关算法与题目讲解
- Today's words
- LINUX命令随记
- AIDL通讯注意事项
- 获取主要变例
- [bzoj4556][TJOI&&HEOI2016]字符串
- Ubuntu下管理启动服务