第七届蓝桥杯个人赛省赛(Java B组)第七题

剪邮票

如图, 有12张连在一起的12生肖的邮票。
图1
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如这两张图中,粉红色所示部分就是合格的剪取。
图2
图3
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

  • 从小到大选取数字的组合(如果不从小到大,从邮票2开始剪和从邮票12开始剪会出现图2相同的情况),再在这些组合里判断相联通的情况。
  • 判断联通:设置一个布尔型的数组来表示是否联通,这里判断条件设置得很巧妙,因为在第一步组合邮票的时候是从0开始的,所以如果两张邮票除以4结果相同而且相差1就说明横排相连,如果相差4就说明纵列相连
  • 最后如果布尔数组内的元素都被赋值为true则说明联通

下面附上代码:

public class ResultFilling7 {
    static int stamps[] = new int[5];

    public static void main(String[] args) {
        int count = 0;
        // 从小到大的顺序剪邮票
        for (stamps[0] = 0; stamps[0] < 12; stamps[0]++) {
            for (stamps[1] = stamps[0] + 1; stamps[1] < 12; stamps[1]++) {
                for (stamps[2] = stamps[1] + 1; stamps[2] < 12; stamps[2]++) {
                    for (stamps[3] = stamps[2] + 1; stamps[3] < 12; stamps[3]++) {
                        for (stamps[4] = stamps[3] + 1; stamps[4] < 12; stamps[4]++) {
                            if (judge()) {
                                count++;
                            }
                        }
                    }
                }
            }
        }
        System.out.println(count); // 最终运行结果:116
    }

    // 判断是否联通
    private static boolean judge() {
        boolean visit[] = new boolean[5];
        dfs(visit, 0);
        return visit[0] && visit[1] && visit[2] && visit[3] && visit[4];
    }

    private static void dfs(boolean[] visit, int i) {
        visit[i] = true;
        for (int j = 0; j < visit.length; j++) {
            // 判断是否横排相连
            if (!visit[j] && (stamps[i] / 4 == stamps[j] / 4) && (stamps[i] == stamps[j] + 1 || stamps[i] == stamps[j] - 1)) {
                dfs(visit, j);
            }
            // 判断是否纵列相连
            if (!visit[j] && (stamps[i] == stamps[j] + 4 || stamps[i] == stamps[j] - 4)) {
                dfs(visit, j);
            }
        }
    }
}

这里参考了obession的解答,并对其代码详细地解释了一下
原文链接=》 蓝桥杯-第七届省赛javaA组-剪邮票
下面是我最初的错误的做法,我是这样想的:

  • 把所有相连的情况用一种数据结构存起来,也就是代码中的HashMap映射,再用一个布尔数组来表示邮票是否被剪,如果能够连续剪5张邮票,则可能的情况数加一,想法是可以的,但是稍加分析就可以看到存在很多问题。
  • main方法里面只写了从1开始剪的情况,那么从其他张邮票开始剪的情况就没有杯考虑到了,另外,如果从各个邮票开始剪,有怎么考虑重叠的情况呢(上面说的剪法不同,剪出的五张连邮相同)。
  • 其实这种想法是来自于上一题,上一题就是用这种想法做出来的,上一题链接=》第七届蓝桥杯个人赛省赛(Java B组)第六题,后面我也没有想该怎么改进了,有想法的朋友欢迎留言。

下面是错误的代码:

public class ResultFilling7 {
    public static int counter = 0;
    public static boolean[] isCut = new boolean[13];
    public static Map<Integer, int[]> map = new HashMap<Integer, int[]>();

    public static void cut(int num, int stamps) {
        if (num == 6) {
            counter++;
            return;
        }
        int[] a = map.get(stamps);
        for (int i = 0; i < a.length; i++) {
            if (!isCut[a[i]]) {
                isCut[a[i]] = true;
                cut(num + 1, a[i]);
                isCut[a[i]] = false;
            }
        }
    }

    public static void main(String[] args) {
        map.put(1, new int[] { 2, 5 });
        map.put(2, new int[] { 1, 3, 6 });
        map.put(3, new int[] { 2, 4, 7 });
        map.put(4, new int[] { 3, 8 });
        map.put(5, new int[] { 1, 6, 9 });
        map.put(6, new int[] { 2, 5, 7, 10 });
        map.put(7, new int[] { 3, 6, 8, 11 });
        map.put(8, new int[] { 4, 7, 12 });
        map.put(9, new int[] { 5, 10 });
        map.put(10, new int[] { 6, 9, 11 });
        map.put(11, new int[] { 7, 10, 12 });
        map.put(12, new int[] { 8, 11 });
        for (int i = 0; i < isCut.length; i++) {
            isCut[i] = false;
        }
        isCut[1] = true;
        cut(1, 1);
        System.out.println(counter);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值