zoukankan      html  css  js  c++  java
  • 毕马威图形数独

    我为什么要写这篇博客

    博主的女朋友(你们别问我为什么会有女朋友)之前去一家公司面试,做到了这个题目。很多公司就把这个逻辑作为一个面试的门槛,这个图形数独做不出来连面试的机会都没有。悄悄的说一下,我女朋友是搞财务的(这TM跟逻辑有啥关系啊,顶多就是搞搞加减乘除)。不扯那么多,我们往下看

    什么是图形数独,请看图形分解

    在这里插入图片描述
    在这里插入图片描述
    就是有四种图形,问号处填什么可以使每行每列的四个图形都不一样。

    分析

    这个不就是一个数独吗?只不过是一个四阶的数独,我们可以把图形看成是1234这四个数字,空的地方用-1表示,我们用数独求解的方式去解决不就行了吗。

    数独怎么解

    我们可以用递归的方式解决
    我们在空闲(-1)的地方依次填写1,2,3,4,如果填写1满足条件,我们就在下个空闲的地方,继续填写,每放入一个数字,我们就要判断冲突,如果冲突,就要在当前空闲的地方填入下个数字,如果四个数字都填写过,我们回退一个空闲区,填入下个数字。以此类推,直到所有空闲都填满为止。

    看不懂没关系,上代码,下面是C#的代码,你们也可以改成Java的

    public class Calc
        {
            private int n;//是n*n的
            private int[,] mp;//二维数组-1表示空的 1~n 表示填入的数据
            private int[,] result; //最终结果
            public int[,] getMap()
            {
                return mp;
            }
    
            /// <summary>
            /// 构造方法传入参数
            /// </summary>
            /// <param name="mp"></param>
            /// <param name="n"></param>
            public Calc(int[,] mp, int n)
            {
                this.mp = mp;
                this.n = n;
                this.result = mp;
            }
    
    
            /// <summary>
            /// 判断某行某列能否放num这个数
            /// </summary>
            /// <param name="row"></param>
            /// <param name="col"></param>
            /// <param name="num"></param>
            /// <returns></returns>
            private bool solve(int row, int col, int num)
            {
                //用于记录row col这个点所在的行列所有出现的数字
                List<int> list = new List<int>();
                for (int i = 0; i < 4; ++i)
                {
                    if (mp[row, i] != -1)
                    {
                        //不存在就放入
                        if (!list.Contains(mp[row, i]))
                        {
                            list.Add(mp[row, i]);
                        }
                    }
                    if (mp[i, col] != -1)
                    {
                        //不存在就放入
                        if (!list.Contains(mp[i, col]))
                        {
                            list.Add(mp[i, col]);
                        }
                    }
                }
                //如果这个数已经出现过,就不能放入
                if (list.Contains(num))
                {
                    return false;
                }
                //没有出现过,就可以放num这个数
                return true;
            }
    
            /// <summary>
            /// 深度优先递归放入数据
            /// </summary>
            /// <param name="cal"></param>
            /// <param name="pel"></param>
            public void dfs(int row, int col)
            {
                //递归结束条件,每次列加一,如果列越界,行加一,列清零
                //如果行越界了,就表示所有的数都填完了,结束遍历,将结果map赋值给result
                if (row == n && col == 0)
                {
                    //将结果map赋值给result
                    setResult();
                    return;
                }
                //下一个点的行列
                int nextRow = row;
                int nextCol = col;
                //判断列是否为最后一个,如果是就变成下一行的第一个
                if (col == (n - 1))
                {
                    nextRow++;
                    nextCol = 0;
                }
                //否则列+1
                else
                {
                    nextCol++;
                }
                //如果当前点已经填了值,填充下一个点
                if (mp[row, col] != -1)
                {
                    dfs(nextRow, nextCol);
                    return;
                }
                //如果当前点没有值,就依次判断是否可以填入1~n
                for (int i = 1; i <= n; i++)
                {
                    //判断row col这个点能否放入i这个数
                    if (solve(row, col, i))
                    {
                        mp[row, col] = i;
                        //能放入就给下个点放入数据
                        dfs(nextRow, nextCol);
                    }
                }
                //如果1~n都不能填,就置为-1,让上一个点继续填入下个数
                mp[row, col] = -1;
            }
    
    
            /// <summary>
            /// 将结果map赋值给result
            /// </summary>
            private void setResult()
            {
                result = new int[n, n];
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        result[i, j] = mp[i, j];
                    }
                }
            }
    
            /// <summary>
            /// 返回最终结果
            /// </summary>
            /// <returns></returns>
            public int[,] getResult()
            {
                dfs(0, 0);
                return result;
            }
        }
    

    方法也有了,接下来不就可以用个界面包装一下了吗

    界面包装

    在这里插入图片描述
    给中间填充区域的每个Label添加点击事件,记录所选的行列(记录在label22中)
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    然后给下面的选择项添加点击事件,点击完后,如果label22中有值,就在那个行列中填充所选的图案
    在这里插入图片描述

    在这里插入图片描述

    点击计算后,将图案转成数字,调用Calc的方案,返回结果,最后将结果显示出来

    int n = 4;
                //获得所有需要填充的数据
                Dictionary<string, Label> dict = new Dictionary<string, Label>();
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        if (array[i, j].Text == "空")
                        {
                            dict.Add(i + "," + j, array[i, j]);
                        }
                    }
                }
                int[,] mp = new int[n, n];
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        string str = array[i, j].Text;
                        if (str == "空")
                            mp[i, j] = -1;
                        else if (str == "▲")
                        {
                            mp[i, j] = 1;
                        }
                        else if (str == "■")
                        {
                            mp[i, j] = 2;
                        }
                        else if (str == "✚")
                        {
                            mp[i, j] = 3;
                        }
                        else if (str == "●")
                        {
                            mp[i, j] = 4;
                        }
                        else
                        {
                            mp[i, j] = 5;
                        }
                    }
                }
                Calc calc = new Calc(mp, n);
                mp = calc.getResult();
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        int num = mp[i, j];
                        if (num == -1)
                        {
                            array[i, j].Text = "空";
                        }
                        else if (num == 1)
                        {
                            array[i, j].Text = "▲";
                        }
                        else if (num == 2)
                        {
                            array[i, j].Text = "■";
                        }
                        else if (num == 3)
                        {
                            array[i, j].Text = "✚";
                        }
                        else if (num == 4)
                        {
                            array[i, j].Text = "●";
                        }
                        else
                        {
                            array[i, j].Text = "★";
                        }
                        if (dict.Keys.Contains(i + "," + j))
                        {
                            array[i, j].ForeColor = Color.Red;
                        }
                    }
                }
    

    以上就是整个代码的解决方法

    为了操作的方便性,我添加了键盘快捷方式

    private void Form1_KeyDown(object sender, KeyEventArgs e)
            {
                if (label22.Text.Length == 0)
                {
                    return;
                }
                string[] tagArray = label22.Text.Split(',');
                int x = Convert.ToInt32(tagArray[0]);
                int y = Convert.ToInt32(tagArray[1]);
                if (e.KeyCode == Keys.NumPad0 || e.KeyCode == Keys.K || e.KeyCode == Keys.N)
                {
                    array[x, y].Text = "空";
                }
                else if (e.KeyCode == Keys.NumPad1 || e.KeyCode == Keys.Y)
                {
                    array[x, y].Text = "●";
                }
                else if (e.KeyCode == Keys.NumPad2 || e.KeyCode == Keys.J)
                {
                    array[x, y].Text = "✚";
                }
                else if (e.KeyCode == Keys.NumPad3 || e.KeyCode == Keys.S)
                {
                    array[x, y].Text = "▲";
                }
                else if (e.KeyCode == Keys.NumPad4 || e.KeyCode == Keys.Z || e.KeyCode == Keys.F)
                {
                    array[x, y].Text = "■";
                }
                else if (e.KeyCode == Keys.NumPad5 || e.KeyCode == Keys.W)
                {
                    array[x, y].Text = "★";
                }
            }
    

    最终附上所有的完整的代码

    Gitee地址

    有了这工具,我女朋友还会怕那些公司让我做这些题吗?

  • 相关阅读:
    jQuery 简单滑动轮播图效果
    西工大:同学你好,回来挂科!
    【入门】产品经理零基础怎么入门?
    【考点】 HashMap,HashTable,CurrentHashMap,LinkedHashMap,TreeMap简述
    P图鬼才们集体上线!高校毕业照P图哪家强?
    【实战】怎样实现前端裁剪上传图片功能
    校招选产品经理岗?给你浇盆水
    战胜70%对手的校招开发岗简历是这个样子的
    两个人遇到熊,装死的和转身跑的,哪个能活下来
    第一份实习工作,我应该学到什么?
  • 原文地址:https://www.cnblogs.com/zjwno1/p/13097325.html
Copyright © 2011-2022 走看看