java蓝桥杯 B组(二)

•    6. 奇怪的分式
上小学的时候,小明经常自己发明新算法。一次,老师出的题目是:
1/4 乘以 8/5  小明居然把分子拼接在一起,分母拼接在一起,答案是:18/45 (参见图1.png)    
老师刚想批评他,转念一想,这个答案凑巧也对啊,真是见鬼!对于分子、分母都是 1~9 中的一位数的情况,还有哪些算式可以这样计算呢?
请写出所有不同算式的个数(包括题中举例的)。
显然,交换分子分母后,例如:4/1 乘以 5/8 是满足要求的,这算做不同的算式。    
但对于分子分母相同的情况,2/2 乘以 3/3 这样的类型太多了,不在计数之列!注意:答案是个整数(考虑对称性,肯定是偶数)。请通过浏览器提交。不要书写多余的内容。


昂。本来上一次是写到这儿的。可是后来写完分析就没时间 了。然后接着写。。

第一部分肯定是遍历了。因为是统计正确解的问题,第二部分是如何化简分数,其实 不用,因为这道题的精度并不高,分数就是除法运算。我们把结果算出来一比较就好了。第三就是排除重复的答案。也不难。用位图法都可以。


第一步 先把所有情况用算法表示出来

如果真的全用循环来算的话。恐怕需要四层这样效率很低。所以我们用空间来换时间


private static int getresult(double start, double end) {
		// TODO Auto-generated method stub
		int result = 0;
		for (double i = start; i <= end; i++) {
			for (double j = start; j <= end; j++) {
				System.out.println(i + "/" + j+"="+(i / j));
			}
		}
		return result;
	}
结果
1.0/1.0=1.0
1.0/2.0=0.5
1.0/3.0=0.3333333333333333
1.0/4.0=0.25
1.0/5.0=0.2
1.0/6.0=0.16666666666666666
1.0/7.0=0.14285714285714285
1.0/8.0=0.125
1.0/9.0=0.1111111111111111

..................

这样就先把所有数都列出来 了。然后存储到一个临时数组里。然后对数组进行操作。


第二步写出判断语句

<span style="font-size:18px;">	private static int getresult(int start, int end) {
		// TODO Auto-generated method stub
		int result = 0;
		String temp[] = new String[(end * end)];
		int index = 0;
		for (int i = start; i <= end; i++) {
			for (int j = start; j <= end; j++) {
				temp[index] = i + "/" + j;
				index++;
			}
		}

		for (int i = 0; i < temp.length; i++) {
			for (int j = i; j < temp.length; j++) {
				if (temp[i].split("/")[0].equals(temp[i].split("/")[1])
						&& temp[j].split("/")[0].equals(temp[j].split("/")[1])) {
					continue;
				}
				System.out.print(temp[i].split("/")[0] + "*"
						+ temp[j].split("/")[0] + "/" + temp[i].split("/")[1]
						+ "/" + temp[j].split("/")[1] + "?=");
				System.out
						.println((10 * dou(temp[i].split("/")[0]) + dou(temp[j]
								.split("/")[0]))
								+ "/"
								+ ((10 * dou(temp[i].split("/")[1]) + dou(temp[j]
										.split("/")[1]))));
				if (dou(temp[i].split("/")[0]) * dou(temp[j].split("/")[0])
						/ dou(temp[i].split("/")[1])
						/ dou(temp[j].split("/")[1]) == (10 * dou(temp[i]
						.split("/")[0]))
						+ dou(temp[j].split("/")[0])
						/ ((10 * dou(temp[i].split("/")[1]) + dou(temp[j]
								.split("/")[1])))) {
					System.out.println(temp[i] + "   " + temp[j]);
				}

			}
		}
		return result;
	}

	public static double dou(String a) {
		return Double.parseDouble(a);
	}</span>

结果:

1*1/1/2?=11.0/12.0  把所有的等式情况都列出来
1*1/1/3?=11.0/13.0
1*1/1/4?=11.0/14.0
1*1/1/5?=11.0/15.0
1*1/1/6?=11.0/16.0
1*1/1/7?=11.0/17.0
1*1/1/8?=11.0/18.0
1*1/1/9?=11.0/19.0
1*2/1/1?=12.0/11.0
1*2/1/3?=12.0/13.0
1*2/1/4?=12.0/14.0
1*2/1/5?=12.0/15.0
1*2/1/6?=12.0/16.0

.........

这时候 就看出代码可读性的重要了。。根本无法调试。。所以要做一下可读性的整理

<span style="font-size:18px;">private static int getresult(int start, int end) {
		// TODO Auto-generated method stub
		int result = 0;
		String temp[] = new String[(end * end)];
		int index = 0;
		for (int i = start; i <= end; i++) {
			for (int j = start; j <= end; j++) {
				temp[index] = i + "/" + j;
				index++;
			}
		}

		for (int i = 0; i < temp.length; i++) {
			for (int j = i; j < temp.length; j++) {
				double a = dou(temp[i].split("/")[0]);
				double b = dou(temp[i].split("/")[1]);
				double c = dou(temp[j].split("/")[0]);
				double d = dou(temp[j].split("/")[1]);
				if (a == b && c == d) {
					continue;
				}
				// System.out.println(a + "/" + b +"             "+ c + "/" +
				// d);
				// System.out.println(a / b * c / d);
				// System.out.println(((10 * a) + c) / ((10 * b) + d));
				if (a / b * c / d == ((10 * a) + c) / ((10 * b) + d)) {
					System.out.println((int) a + "/" + (int) b + "        "
							+ (int) c + "/" + (int) d);
				}

			}
		}
		return result;
	}

	public static double dou(String a) {
		return Double.parseDouble(a);
	}</span>

这样一下子就明白了。

结果:

1/2        5/4
1/4        8/5
1/6        4/3
1/6        6/4
1/9        9/5
2/1        4/5
2/6        6/5
4/1        5/8
4/9        9/8

结果为奇数。不合题意。。看结果并不是对称的。这样就很可能是没有循环到那个情况

整理一下结果

1/2        5/4 ===    2/1        4/5

1/4        8/5===4/1        5/8

1/6        4/3===?6/1    3/4 这个是否未循环到看一下输出。

1/6        6/4===?

把for循环里边j==i改成了j==0本来以为用前一种可 以避免重复。。没想到弄巧成拙了

结果2:

1/2        5/4
1/4        8/5
1/6        4/3
1/6        6/4
1/9        9/5
2/1        4/5
2/6        6/5
4/1        5/8
4/9        9/8
6/1        3/4
6/1        4/6
6/2        5/6
9/1        5/9
9/4        8/9

这回对了。。


•    7. 扑克序列
AA223344, 一共4对扑克牌。请你把它们排成一行。
    要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌。
4A3A2432
2342A3A4
   请填写出所有符合要求的排列中,字典序最小的那个。

例如:22AA3344 比 A2A23344 字典序小。当然,它们都不是满足要求的答案。
2342A3A4
请通过浏览器提交答案。“A”一定不要用小写字母a,也不要用“1”代替。字符间一定不要留空格。

这题的难点 是如何列出所有的结果,第一种方法 按规则罗列结果显然有些难。第二种就是罗列所有结果找出符合规则的组。

应该是排列组合里边的A几几

那么现在的问题就变成了如何用算法实现A排列组合

平常思维 是

从8个里挑一个放到第一个。

那么要想实现遍历。就是挑8个各放在第一组。这里有4个是重复的。所以挑4个

第二步从剩下的7个里再遍历放在第二个。

private static int getresult(int start, int end) {
		// TODO Auto-generated method stub
		int result = 0;
		char[] temp = { 'A', 'A', '2', '2', '3', '3', '4', '4' };
		StringBuilder t = new StringBuilder();
		int [] intt=new int[8];
		for (int i = 0; i < temp.length; i++) {
			t.append(temp[i]);
			intt[0]=i;
			for (int j = 0; j < temp.length; j++) {
				if (intt[0]==j) {
					continue;
				}
				t.append(temp[j]);
				intt[1]=j;
				for (int j2 = 0; j2 < temp.length; j2++) {
					if (intt[0]==j2||intt[1]==j2) {
						continue;
					}
					t.append(temp[j]);
					intt[1]=j;
					for (int k = 0; k < intt.length; k++) {
						.............
					}
				}
			}
		}
		return result;
	}


用这种方式虽然能实现,但是代码长不好读也不美观。不过也许在比赛中没时间想别的那就只能这种了

上边这种方法特别像递归。所以我们试试用递归实现

private static int getresult(int start, int end) {
		// TODO Auto-generated method stub
		int result = 0;
		char[] temp = { 'A', 'A', '2', '2', '3', '3', '4', '4' };
		StringBuilder t = new StringBuilder();
		int[] intt = new int[8];
		for (int i = 0; i < temp.length; i++) {
			append(t, intt, temp, 0);
		}
		return result;
	}

	private static void append(StringBuilder t, int[] intt, char[] temp,
			int index) {
		// TODO Auto-generated method stub
		if (index ==7) {
			System.out.println(t);
		}
		for (int i = 0; i < temp.length; i++) {
			if (isok(intt, i))
				t.append(temp[i]);
			else
				continue;
			if (index > 7) {
				index = 7;
			} else
				index++;
			intt[index] = i;
			append(t, intt, temp, index);
		}
	}

	private static boolean isok(int[] intt, int i) {
		// TODO Auto-generated method stub
		for (int c : intt) {
			if (i == c) {
				return false;
			}
		}
		return true;
	}
 
本来打算用递归实现 ,后来发现递归其实上是深度优先的。这样就造成了不可循环性。因为intt做为存放已用字符的下标载体将会再第一次递归完成后充满。那么也就是说每次递归完成后都要将这个数组清空才行?或者是退格一个字符。

其实 刚才 想这个的时候 我已经想到其实 不必排字符了。直接把下标做个A排列就好了。明天再更





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值