抖音上农民伯伯出的题,真的会难倒清华北大的高材生吗?

今天是元旦放假第一天,想着多睡会,不想改论文了。赖床的时候刷了刷抖音,发现有很多视频反复出现这么一个题目。声称是一道农民工出的题目,难倒了几万清华北大的高材生。

说实话,这些年来这种UC式的标题让人很疲劳,标题反正是一个比一个夸张。我仔细看了看题目,分析了一下。题目如下所示。

 

 

首先声明一下我的结论,那就是这个“农民大伯”出的题目不光清华北大的高材生一笔画不出来,欧拉莱布尼茨掀开棺材板出来也是无能为力。

这个题目实际上就是图论里寻找到一条起点到终点的哈密尔顿路径的问题。哈密尔顿路径是在1859年,由爱尔兰数学家哈密尔顿提出的周游世界游戏中的一个数学概念。其定义就是在一个图中,遍历每个顶点一次且仅一次的路径称为哈密尔顿路径。

我查阅了一下哈密尔顿路径判定的必要条件,发现似乎都不能应用到这个题目上来。要从数学证明上来解决对我这种图论已经忘的差不离的菜鸡来说还是有点难度。所以我就借助网上的遍历穷举哈密尔顿路径的方法对于这个问题进行分析,解决。

 

首先我先将每个格子看成一个顶点,由于图里不能有斜线所以我们的问题就是在下面这个图中求取一条从顶点1到顶点13的哈密尔顿路径(通过其他所有顶点并且只能通过一次)。

 

 

 

把这个图用邻接矩阵表示出来(18个点就是18*18的矩阵,还是有点大噻)

 

 

然后用https://blog.csdn.net/zhangyifei521/article/details/53283028里的Java源码,把里头的邻接矩阵X换成上面那个,源码如下所示。

 

package tiktok;

public class hamilton {

    public static void main(String[] args) {
        hamilton obj = new hamilton();

        int[][] x = {
                {0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
                {1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                {0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0},
                {0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0},
                {0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0},
                {0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0},
                {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1},
                {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0}   
        
        };

//        int[][] y = { { 0, 1, 0, 0, 0, 1 }, 
//                      { 1, 0, 1, 0, 0, 1 },
//                      { 0, 1, 0, 1, 1, 0 }, 
//                      { 0, 0, 1, 0, 0, 0 },
//                      { 0, 0, 1, 0, 0, 1 }, 
//                      { 1, 1, 0, 0, 1, 0 } };
//
//        int[][] z = { { 0, 1, 1, 0, 0, 1 }, { 1, 0, 1, 0, 0, 0 },
//                { 1, 1, 0, 1, 0, 1 }, { 0, 0, 1, 0, 1, 0 },
//                { 0, 0, 0, 1, 0, 1 }, { 1, 0, 1, 0, 1, 0 } };

        obj.allHamiltonPath(x); // list all Hamiltonian paths of graph
        // obj.HamiltonPath(z,1); //list all Hamiltonian paths start at point 1

    }

    static int len;
    static int[] path;
    static int count = 0;

    public void allHamiltonPath(int[][] x) { // List all possible Hamilton path
                                                // in the graph
        len = x.length;
        path = new int[len];
        int i;
        for (i = 0; i < len; i++) { // Go through column(of matrix)
            path[0] = i + 1;
            findHamiltonpath(x, 0, i, 0);
        }
    }

//  public void HamiltonPath(int[][] x, int start) { // List all possible
//                                                      // Hamilton path with
//                                                      // fixed starting point
//      len = x.length;
//      path = new int[len];
//      int i;
//      for (i = start - 1; i < start; i++) { // Go through row(with given
//                                              // column)
//          path[0] = i + 1;
//          findHamiltonpath(x, 0, i, 0);
//      }
//  }

    private void findHamiltonpath(int[][] M, int x, int y, int l) {

        int i;
        for (i = x; i < len; i++) { // Go through row

            if (M[i][y] != 0) { // 2 point connect

                if (detect(path, i + 1))// if detect a point that already in the
                                        // path => duplicate
                    continue;

                l++; // Increase path length due to 1 new point is connected
                path[l] = i + 1; // correspond to the array that start at 0,
                                    // graph that start at point 1
                if (l == len - 1) {// Except initial point already count
                                    // =>success connect all point
                    count++;
                    if (count == 1)
                        System.out.println("Hamilton path of graph: ");
                    display(path);
                    l--;
                    continue;
                }

                M[i][y] = M[y][i] = 0; // remove the path that has been get and
                findHamiltonpath(M, 0, i, l); // recursively start to find new
                                                // path at new end point
                l--; // reduce path length due to the failure to find new path
                M[i][y] = M[y][i] = 1; // and tranform back to the inital form
                                        // of adjacent matrix(graph)
            }
        }
        path[l + 1] = 0; // disconnect two point correspond the failure to find
                            // the..
    } // possible hamilton path at new point(ignore newest point try another
        // one)

    public void display(int[] x) {

        System.out.print(count + " : ");
        for (int i : x) {
            System.out.print(i + " ");
        }
        System.out.println();
    }

    private boolean detect(int[] x, int target) { // Detect duplicate point in
                                                    // Halmilton path
        boolean t = false;
        for (int i : x) {
            if (i == target) {
                t = true;
                break;
            }
        }
        return t;
    }
}

 

 

运行结果会把所有的哈密尔顿路径(不限制起点终点)都打印出来,一共有672条哈密尔顿路径。

 

 

但是如果将起点限制为顶点1,终点限制为顶点13,那么没有一条哈密尔顿路径可以满足此条件。(起点为1的哈密尔顿路径有78条,但是没有一条终点为13)

 

 

所以,通过穷举遍历的方法,这道农民大伯出的题目是无解的。当然各位抖音上的大神通过折纸,画到外面的方式来增加/减少图中的顶点,也许确实可以找到这样一条路径,但是可能也违背了农民大伯的初衷了吧。

 

另外,如果有大佬知道怎么数学证明这个问题的话,也欢迎在评论里留言,大家一起交流学习。

 

转载于:https://www.cnblogs.com/wojiaozhangtao/p/10200365.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个相对复杂的问,需要使用树的相关知识和Java编程技术实现。下面是一个简单的实现示例,供您参考: ``` import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Scanner; public class FamilyTree { // 家族成员类 static class Member { String name; // 姓名 Member father; // 父亲 List<Member> children; // 孩子 public Member(String name) { this.name = name; this.children = new ArrayList<>(); } // 添加孩子 public void addChild(Member child) { children.add(child); child.father = this; } } public static void main(String[] args) { // 初始族谱 Member root = new Member("祖先"); Member m1 = new Member("父亲"); Member m2 = new Member("叔叔"); Member m3 = new Member("伯伯"); Member m4 = new Member("儿子1"); Member m5 = new Member("儿子2"); Member m6 = new Member("侄子1"); Member m7 = new Member("侄子2"); Member m8 = new Member("侄孙1"); Member m9 = new Member("侄孙2"); Member m10 = new Member("孙子1"); Member m11 = new Member("孙子2"); root.addChild(m1); root.addChild(m2); root.addChild(m3); m1.addChild(m4); m1.addChild(m5); m2.addChild(m6); m2.addChild(m7); m6.addChild(m8); m7.addChild(m9); m4.addChild(m10); m5.addChild(m11); // 构建家族成员Map,方便查询 Map<String, Member> members = new HashMap<>(); members.put(root.name, root); members.put(m1.name, m1); members.put(m2.name, m2); members.put(m3.name, m3); members.put(m4.name, m4); members.put(m5.name, m5); members.put(m6.name, m6); members.put(m7.name, m7); members.put(m8.name, m8); members.put(m9.name, m9); members.put(m10.name, m10); members.put(m11.name, m11); // 测试查询和修改功能 Scanner scanner = new Scanner(System.in); while (true) { System.out.println("请输入要查询或修改的家族成员姓名:"); String name = scanner.nextLine(); Member member = members.get(name); if (member == null) { System.out.println("找不到该成员!"); continue; } System.out.println("该成员的父亲是:" + (member.father == null ? "无" : member.father.name)); System.out.println("该成员的孩子有:"); for (Member child : member.children) { System.out.println(child.name); } System.out.println("请选择要进行的操作:1-新增孩子,2-退"); int option = scanner.nextInt(); scanner.nextLine(); if (option == 1) { System.out.println("请输入要新增孩子的姓名:"); String childName = scanner.nextLine(); Member child = new Member(childName); member.addChild(child); members.put(childName, child); System.out.println("新增孩子成功!"); } else if (option == 2) { break; } else { System.out.println("无效的操作!"); } } } } ``` 在这个示例中,我们使用了树的数据结构来存储家族成员的族谱,每个成员都是一个节点,有父亲和孩子。构建家族成员Map可以方便地查询和修改家族成员。在主函数中,我们先构建了一个初始的家族成员,然后通过Scanner从键盘输入要查询或修改的成员姓名,查询该成员的父亲和孩子,并提供了新增孩子的功能,直到用户选择退

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值