鸽子和兔子

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(0+" "+0 + " " + 0);
           } else {
               System.out.println(1+" "+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();
   }
}

时间: 2024-10-07 16:20:32

鸽子和兔子的相关文章

1004: 1、2、3、4、5...

1004: 1.2.3.4.5... Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1801  Solved: 503[Submit][Status][Web Board] Description 浙江工商大学校园里绿树成荫,环境非常舒适,因此也引来一批动物朋友来此居住.童心未泯的redraiment就经常带些碎面包什么的去广场喂鸽子和兔子,并和它们玩耍.一点也不像大学生,还是一副老不正经的样子,呵呵.随着鸽子和兔子数目的增多,redraiment

递归函数____斐波拉契数列____出生2个月后小兔子可以生小小兔子

2017-09-17 22:41:44 递归     ____函数自己调用自己,又可以理解为自己的事情自己做.    如果觉得难以理解,可以把理解成这个函数调用了一个函数,只是这个函数和自己长得一模一样. ---------------------------------------------------------------------------------------     拿一对刚出生的小兔子编故事.     假设,一对刚出生的小兔子,第一个月没有繁殖能力,两个月后生下一对兔子.

bzoj1001 [BeiJing2006]狼抓兔子

1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 23723  Solved: 5981[Submit][Status][Discuss] Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M

【吃炸弹的鸽子UVA10765-双联通模板】

·从前有一个鸽子Lence,它吃了一个炸弹,然后有人出了这道题. ·英文题,述大意:        给出一张连通无向图,求出:对于每个点,删去这个点(以及它相连的边以后)时,当前图中的连通块数量,这个值作为该点的Lence值.输出根据Lence值从大到小(相同时标号从小到大)的前m个点和它的Lence值. ·分析:       关于连通块问题,可以寻得三种方法:       ①嘎嘣脆算法(Gabow)②塔尔杨算法(Tarjan)③Kosaraju算法.        此处大米饼采用Tarjan算

js算法集合(二) javascript实现斐波那契数列 (兔子数列) Javascript实现杨辉三角

js算法集合(二)  斐波那契数列.杨辉三角 ★ 上一次我跟大家分享一下做水仙花数的算法的思路,并对其扩展到自幂数的算法,这次,我们来对斐波那契数列和杨辉三角进行研究,来加深对Javascript的理解. 一.Javascript实现斐波那契数列 ①要用Javascript实现斐波那契数列,我们首先要了解什么是斐波那契数列:斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为

养兔子Fibo函数优化

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> /* var cache = (function createCache() { var data = []; return function c

【BZOJ 1001】[BeiJing2006]狼抓兔子

Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)<==>(x+1,y+1) 道路上的权值表示这条路上最多能够通过的兔子数,道路是

5.16 兔子生兔子,日期时间练习

namespace ConsoleApplication8 { class Program { static void Main(string[] args) { #region // //有一对幼兔,幼兔一个月后长成小兔,小兔一个月后长成成兔.并生下一对幼兔, //// 问几年后,有多少对幼兔,多少对小兔,多少对成兔,兔子总数是多少? // // 成兔每月生一对幼兔. // Console.WriteLine("请输入月份"); // int MM = int.Parse(Conso

鸽子洞原理或者称为抽屉原理

原理概述: 有n只鸽子和m个鸽洞,所有鸽子都住在鸽洞里,如果n>m,那么至少有二只鸽子必须住在同一鸽洞里. 函数观点: 把鸽子看成是定义域A中元素ai,鸽洞看成是值域B中的元素bj,鸽子住鸽洞作为函数关系. 鸽洞原理: 设f是从有限集A到有限集B的函数,若|A|>|B|,则必有a1,a2∈A,a1≠a2,使f(a1)=f(a2)=b∈Bf 包含于B(Bf是象域). 反证:若对任意a1,a2∈A,a1≠a2,f(a1)≠f(a2),|A|=|Bf|≤|B|与|A|>|B|矛盾 注: 鸽洞原