`
spacefly
  • 浏览: 279439 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

小学数学竞赛题:1-9 填充 3 * 3 格

    博客分类:
  • java
阅读更多
用 java 实现这么 一道 小学数学竞赛题:
   用1-9 填充 3 * 3 格,使得 横、竖、斜 8条线上数字之和都相等。

java代码:
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 用 1 - 9 数字 填充 3 * 3 格,使得 横3、竖3、斜2 共8道,每道之和都相等; 
 */
public class Test {
	public static void main(String[] args) {
		Long startT = System.currentTimeMillis();
		Set<NineGrid> result = new LinkedHashSet<NineGrid>();
		int i = 0;
		for (int x9 = 1; x9 <= 9; x9++) {
			for (int x8 = 1; x8 <= 9; x8++) {
				if (x8 != x9) {
					for (int x7 = 1; x7 <= 9; x7++) {
						if (x7 != x9 && x7 != x8) {
							for (int x6 = 1; x6 <= 9; x6++) {
								if (x6 != x9 && x6 != x8 && x6 != x7) {
									// 分析知 中间的数字 必须为 5
									for (int x5 = 5; x5 <= 5; x5++) {
										if (x5 != x9 && x5 != x8 && x5 != x7 && x5 != x6) {
											for (int x4 = 1; x4 <= 9; x4++) {
												if (x4 != x9 && x4 != x8 && x4 != x7 && x4 != x6 && x4 != x5) {
													for (int x3 = 1; x3 <= 9; x3++) {
														if (x3 != x9 && x3 != x8 && x3 != x7 && x3 != x6 && x3 != x5 && x3 != x4) {
															for (int x2 = 1; x2 <= 9; x2++) {
																if (x2 != x9 && x2 != x8 && x2 != x7 && x2 != x6 && x2 != x5 && x2 != x4 && x2 != x3) {
																	for (int x1 = 1; x1 <= 9; x1++) {
																		if (x1 != x9 && x1 != x8 && x1 != x7 && x1 != x6 && x1 != x5 && x1 != x4 && x1 != x3
																				&& x1 != x2) {
																			NineGrid gd = new NineGrid();
																			gd.value[8] = x9;
																			gd.value[7] = x8;
																			gd.value[6] = x7;
																			gd.value[5] = x6;
																			gd.value[4] = x5;
																			gd.value[3] = x4;
																			gd.value[2] = x3;
																			gd.value[1] = x2;
																			gd.value[0] = x1;
																			if (gd.isRight()) {
																				result.add(gd);
																			}
																			++i;
																		}
																	}
																}
															}
														}
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
		for (Iterator<NineGrid> it = result.iterator(); it.hasNext();) {
			NineGrid _ng = (NineGrid) it.next();
			_ng.printNg();
		}
		Long endT = System.currentTimeMillis();
		System.out.println("Over, " + result.size() + " result, " + i + " try, " + (endT - startT) + " milliseconds.");
	}
}

/**
 * 3*3格 类
 */
class NineGrid {
	int[] value = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };

	public void printNg() {
		System.out.println();
		for (int i = 8; i >= 0; i--) {
			System.out.print(value[i] + "\t");
			if (i % 3 == 0) {
				System.out.println();
			}
		}
	}

	/** 判断 1 - 9 填充后是否满足条件 */
	public boolean isRight() {
		int sum = (value[0] + value[1] + value[2] + value[3] + value[4] + value[5] + value[6] + value[7] + value[8]) * 2
				+ (value[8] + value[6] + value[2] + value[0]) + value[4] * 2;
		if (sum % 8 != 0) {
			return false;
		}
		int eq = sum / 8;
		if ((value[8] + value[7] + value[6] == eq) && (value[5] + value[4] + value[3] == eq) && (value[2] + value[1] + value[0] == eq)
				&& (value[8] + value[5] + value[2] == eq) && (value[7] + value[4] + value[1] == eq) && (value[6] + value[3] + value[0] == eq)
				&& (value[8] + value[4] + value[0] == eq) && (value[6] + value[4] + value[2] == eq)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 用 hashCode 值来判断是否相等;
	 */
	public boolean equals(Object o) {
		if (o == null || o.getClass() != this.getClass()) {
			return false;
		}
		NineGrid ng = (NineGrid) o;
		if (this.hashCode() == ng.hashCode()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 4个角的每种“组合”对应一个不同的 hashCode 值,
	 * 这里的“组合”是数学中“排列、组合”的“组合”;
	 */
	public int hashCode() {
		int ez0, ez1, st0, st1;
		if (value[8] > value[0]) {
			ez0 = value[0];
			ez1 = value[8];
		} else {
			ez0 = value[8];
			ez1 = value[0];
		}
		if (value[6] > value[2]) {
			st0 = value[2];
			st1 = value[6];
		} else {
			st0 = value[6];
			st1 = value[2];
		}
		int[] corners = { 0, 0, 0, 0 };
		if (ez0 < st0) {
			corners[0] = ez0;
			corners[1] = st0;
			corners[2] = st1;
			corners[3] = ez1;
		} else {
			corners[0] = st0;
			corners[1] = ez0;
			corners[2] = ez1;
			corners[3] = st1;
		}
		return (int) (corners[0] + corners[1] * 10 + corners[2] * 1e2 + corners[3] * 1e3);
	}
}



看了各位的解答,发现我的算法不够精简,导致计算次数过多;
撇开算法和计算次数不改,看了 几位对 Arrays 和 Collections 类的使用,我重写了下 NineGrid.java 类;
重写后的 NineGrid.java:
class NineGrid {
	int[] value = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };

	public void printNg() {
		System.out.println();
		for (int i = 8; i >= 0; i--) {
			System.out.print(value[i] + "\t");
			if (i % 3 == 0) {
				System.out.println();
			}
		}
	}

	/** 判断 1 - 9 填充后是否满足条件 */
	public boolean isRight() {
		int sum = (value[1] + value[3] + value[5] + value[7]) * 2 + (value[8] + value[6] + value[2] + value[0]) * 3 + value[4] * 4;
		if (sum % 8 != 0) {
			return false;
		}
		int eq = sum / 8;
		if ((value[8] + value[7] + value[6] == eq) && (value[5] + value[4] + value[3] == eq) && (value[2] + value[1] + value[0] == eq)
				&& (value[8] + value[5] + value[2] == eq) && (value[7] + value[4] + value[1] == eq) && (value[6] + value[3] + value[0] == eq)
				&& (value[8] + value[4] + value[0] == eq) && (value[6] + value[4] + value[2] == eq)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 用 hashCode 值来判断是否相等;
	 */
	public boolean equals(Object o) {
		if (o == this) {
			return true;
		}
		if (o == null || o.getClass() != this.getClass()) {
			return false;
		}
		NineGrid ng = (NineGrid) o;
		if (this.hashCode() == ng.hashCode()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 4个角的每种“组合”对应一个不同的 hashCode 值,
	 * 这里的“组合”是数学中“排列、组合”的“组合”;
	 */
	public int hashCode() {
		List<Integer> li = Arrays.asList(value[0], value[2], value[6], value[8]);
		Collections.sort(li);
		return (int) (li.get(0) + li.get(1) * 10 + li.get(2) * 1e2 + li.get(3) * 1e3);
	}
}


分享到:
评论
16 楼 Eastsun 2009-07-16  
速度一点的:
import java.util.*;
import static java.util.Arrays.*;
import static java.util.Collections.*;

public class A {
    public static void main(String[] args) {
        List<Integer> nums = asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        for(int x1: nums) for(int x2: nums)
        for(int x4: nums) for(int x5: nums)
        {
            int x3 = 15 - x1 - x2;
            int x6 = 15 - x4 - x5;
            int x7 = 15 - x1 - x4;
            int x8 = 15 - x2 - x5;
            int x9 = 15 - x3 - x6;
            List<Integer> nls = new ArrayList<Integer>(asList(x1,x2,x3,x4,x5,x6,x7,x8,x9));
            sort(nls);
            if(!nls.equals(nums)) continue;
            if(x1 + x5 + x9 != 15) continue;
            if(x3 + x5 + x7 != 15) continue;
            System.out.println();
            System.out.println(asList(x1,x2,x3));
            System.out.println(asList(x4,x5,x6));
            System.out.println(asList(x7,x8,x9));
        }
        
    }
}
15 楼 night_stalker 2009-07-16  
动态规划 …… 3 x 3 比较小,体现不出递归的简洁性,就用比较详细的写法吧 ……

s = 15
a = 1..9

(a1 = a.to_a ).each{|x1|
(a2 = a1-[x1]).each{|x2|
(a3 = a2-[x2]).each{|x3|
  next if (x1+x2+x3 != s)

(a4 = a3-[x3]).each{|x4|
(a5 = a4-[x4]).each{|x5|
(a6 = a5-[x5]).each{|x6|
  next if (x4+x5+x6 != s)

(a7 = a6-[x6]).each{|x7|
  next if (x1+x4+x7 != s)
  next if (x3+x5+x7 != s)

(a8 = a7-[x7]).each{|x9|
  next if (x3+x6+x9 != s)
  next if (x1+x5+x9 != s)
  x8 = (a8-[x9])[0]
  p [x1,x2,x3],[x4,x5,x6],[x7,x8,x9]
  puts 
}} }}} }}}
14 楼 RednaxelaFX 2009-07-16  
Eastsun 写道
只能说楼主用java写的很麻烦。。
把你的用java翻译一下,也不用什么Linq
当然效率同样极其低下

嗯,不错不错,赞一个 ^ ^
lazy eval + inlining的效果使得出来的东西确实基本上是一样的
不过既然用上了static import,干脆连System.out.println也拉进来,下面看起来更清爽 =v=
13 楼 Eastsun 2009-07-16  
RednaxelaFX 写道
啊,楼主只是要穷举而已?穷举的话用Java真够麻烦的 OTL
咱们用C#做效率更低的穷举来看看:
using System;
using System.Linq;

static class Program {
    static void Main(string[] args) {
        var candidateNumbers = new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        var results = from x1 in candidateNumbers
                      from x2 in candidateNumbers
                      from x3 in candidateNumbers
                      from x4 in candidateNumbers
                      from x5 in candidateNumbers
                      from x6 in candidateNumbers
                      from x7 in candidateNumbers
                      from x8 in candidateNumbers
                      from x9 in candidateNumbers
                      let r = new [] { x1, x2, x3, x4, x5, x6, x7, x8, x9 }
                      where r.Distinct().Count() == 9
                      let r1 = x1 + x2 + x3
                      let r2 = x4 + x5 + x6
                      let r3 = x7 + x8 + x9
                      let r4 = x1 + x4 + x7
                      let r5 = x2 + x5 + x8
                      let r6 = x3 + x6 + x9
                      let r7 = x1 + x5 + x9
                      let r8 = x3 + x5 + x7
                      where (new [] { r1, r2, r3, r4, r5, r6, r7, r8 }).Distinct().Count() == 1
                      select r;
        foreach (var r in results) {
            Console.WriteLine("{0} {1} {2}", r[0], r[1], r[2]);
            Console.WriteLine("{0} {1} {2}", r[3], r[4], r[5]);
            Console.WriteLine("{0} {1} {2}", r[6], r[7], r[8]);
            Console.WriteLine();
        }
    }
}

easy things easy, hard things possible


只能说楼主用java写的很麻烦。。
把你的用java翻译一下,也不用什么Linq
当然效率同样极其低下:

import java.util.*;
import static java.util.Arrays.*;

public class S {
    public static void main(String[] args) {
        int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        for(int x1: nums) for(int x2: nums) for(int x3: nums)
        for(int x4: nums) for(int x5: nums) for(int x6: nums)
        for(int x7: nums) for(int x8: nums) for(int x9: nums)
        {
            if(new HashSet(asList(x1,x2,x3,x4,x5,x6,x7,x8,x9)).size() < 9) continue;
            int r1 = x1 + x2 + x3;  
            int r2 = x4 + x5 + x6; 
            int r3 = x7 + x8 + x9;  
            int r4 = x1 + x4 + x7;  
            int r5 = x2 + x5 + x8;  
            int r6 = x3 + x6 + x9;  
            int r7 = x1 + x5 + x9; 
            int r8 = x3 + x5 + x7;
            if(new HashSet(asList(r1,r2,r3,r4,r5,r6,r7,r8)).size() > 1) continue;
            System.out.println();
            System.out.println(asList(x1,x2,x3));
            System.out.println(asList(x4,x5,x6));
            System.out.println(asList(x7,x8,x9));
        }
        
    }
}

12 楼 night_stalker 2009-07-16  
穷举嘛 ……
for(int i=123456789;i<1000000000;i++) {
  ...
}
11 楼 RednaxelaFX 2009-07-16  
啊,楼主只是要穷举而已?穷举的话用Java真够麻烦的 OTL
咱们用C#做效率更低的穷举来看看:
using System;
using System.Linq;

static class Program {
    static void Main(string[] args) {
        var candidateNumbers = new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        var results = from x1 in candidateNumbers
                      from x2 in candidateNumbers
                      from x3 in candidateNumbers
                      from x4 in candidateNumbers
                      from x5 in candidateNumbers
                      from x6 in candidateNumbers
                      from x7 in candidateNumbers
                      from x8 in candidateNumbers
                      from x9 in candidateNumbers
                      let r = new [] { x1, x2, x3, x4, x5, x6, x7, x8, x9 }
                      where r.Distinct().Count() == 9
                      let r1 = x1 + x2 + x3
                      let r2 = x4 + x5 + x6
                      let r3 = x7 + x8 + x9
                      let r4 = x1 + x4 + x7
                      let r5 = x2 + x5 + x8
                      let r6 = x3 + x6 + x9
                      let r7 = x1 + x5 + x9
                      let r8 = x3 + x5 + x7
                      where (new [] { r1, r2, r3, r4, r5, r6, r7, r8 }).Distinct().Count() == 1
                      select r;
        foreach (var r in results) {
            Console.WriteLine("{0} {1} {2}", r[0], r[1], r[2]);
            Console.WriteLine("{0} {1} {2}", r[3], r[4], r[5]);
            Console.WriteLine("{0} {1} {2}", r[6], r[7], r[8]);
            Console.WriteLine();
        }
    }
}

easy things easy, hard things possible
10 楼 logicgate 2009-07-15  
这个有固定算法的。任意n*n(n为奇数)的我都会写。
9 楼 playfish 2009-07-15  
呃。。我还以为帖子的代码是故意写成这样来搞笑的。。。。
8 楼 kimmking 2009-07-15  
幸存者 的解法对所有的奇数成立。

偶数还没有通用解法
7 楼 night_stalker 2009-07-15  
<p>4 X 4 的解法:</p>
<p> </p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;">1</span>   2   3  <span style="color: #ff6600;">4</span><br>5  <span style="color: #0000ff;">6</span>   <span style="color: #ff6600;">7</span>  8<br>9  <span style="color: #ff6600;">10</span> <span style="color: #0000ff;">11</span> 12<br><span style="color: #ff6600;">13</span> 14 15 <span style="color: #0000ff;">16</span><br></span></p>
<p> </p>
<p>翻转对角线,完成。</p>
<p> </p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;">16</span> 2   3  <span style="color: #ff6600;">13</span><br>
5  <span style="color: #0000ff;">11</span> <span style="color: #ff6600;">10</span> 8<br>
9  <span style="color: #ff6600;">7</span>  <span style="color: #0000ff;">6</span>  12<br><span style="color: #ff6600;">4</span>  14 15 <span style="color: #0000ff;">1</span><br></span></p>
<p> </p>
<p> </p>
<p>8 X 8 还有个国际象棋马遍历的解法 ……</p>
6 楼 gof95 2009-07-15  
洛河图..
5 楼 幸存者 2009-07-15  
night_stalker 写道
笑死我了 …… 写程序的时间比人脑穷举长 ……

不过这个问题,古书上就有解法。


先斜着按顺序填下数字
  1
 4 2
7 5 3
 8 6
  9


上下交换,左右交换
  9
 4 2
3 5 7
 8 6
  1


然后把上下左右缩回去
492
357
816


对 4 x 4 同样成立

4 X 4 最后一步怎么缩回去?

对于 N X N 的格子,只要N为奇数,有一个非常简单的办法:
step 1:
在第一排中间那个格子写上1
_ 1 _
_ _ _
_ _ _


step 2:
往右上依次写上234...,若是第一排则跳到最下一排,若是最右一列则跳到第一列
_ 1 _
3 _ _
_ _ 2

若右上已经被填,则下移一排
_ 1 6
3 5 _
4 _ 2

重复上一步
8 1 6
3 5 7
4 9 2

4 楼 xyh 2009-07-15  
楼主的算法太复杂了, 应该尽量用集合,减少复杂度
3 楼 lw223 2009-07-15  
信曾哥,会做题
2 楼 Eastsun 2009-07-15  
orz..
1 楼 night_stalker 2009-07-15  
笑死我了 …… 写程序的时间比人脑穷举长 ……

不过这个问题,古书上就有解法。


先斜着按顺序填下数字
  1
 4 2
7 5 3
 8 6
  9


上下交换,左右交换
  9
 4 2
3 5 7
 8 6
  1


然后把上下左右缩回去
492
357
816


对 4 x 4 同样成立

相关推荐

Global site tag (gtag.js) - Google Analytics