导航

一道面试题

Posted on 2007-11-29 15:06  da.da  阅读(1098)  评论(8)    收藏  举报

 

如下图片input.bmp,里面是一个迷宫,用程序算出一条从入口到出口的路径,

input

还给出了一个示例图片

sample

 

说实话,刚开始我看到这个题目的时候,真有点蒙了,这是什么啊,尤其是图片,在我的邮件里那么模糊的一片。而且没有什么说明,要求就是要给出一个求解的算法,并且能有输出结果。

不过还好经过一天的努力我最终还是把这个程序给写出来了,中间我还找出自己上学时的数据结构的课本来现学了半天(不知这算不算作弊^_^).比较郁闷的是我为了是程序运行起来更好看,我用了实时查找路径显示(可以通过把SearchPath.cs中第76行“_picBox.Image = _image;”注释掉,把第157行“//_picBox.Image = _image;”注释取消来实现),这样我忽略了一个问题就是在线程里不能用到界面控件,因为我的机器运行比较慢不会出错(我也不知道为什么),但到运行比较快的机器上就不行了,就会抛出异常,到现在我也没想出办法解决,如果有那位高手有办法解决的话,希望能告诉我,我将非常感谢。

当时也是因为时间原因没有进行代码优化,后来没有优化是因为我的懒惰,在这里自我批评一下,如果有感兴趣的看到我写的不好的地方也非常希望您能告诉我,不胜感激!

如下是我的程序源码:

MainForm.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;

namespace Maze
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }
        ISearchPath _searchPath;
        DateTime _start;
        System.Timers.Timer _timer;
        private void toolBtnStart_Click(object sender, EventArgs e)
        {
            _searchPath = new SearchPath(picBox, new Point(608, 210), new Point(8, 210));
            //_searchPath = new SearchPathTopFirst(picBox, new Point(608, 210), new Point(8, 208));
            System.Threading.Thread t = new Thread(new ThreadStart(_searchPath.GetPath));
            t.Start();
            //StartTime();
        }

        private void StartTime()
        {
            _start = System.DateTime.Now;
            _timer = new System.Timers.Timer(10);
            _timer.Elapsed += new System.Timers.ElapsedEventHandler(PrintTime);
            _timer.Enabled = true;
            _timer.Start();           
        }

        private void PrintTime(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (!_searchPath.IsEnd)
            {
                TimeSpan ts1 = new TimeSpan(DateTime.Now.Ticks);
                TimeSpan ts2 = new TimeSpan(_start.Ticks);
                TimeSpan ts = ts1.Subtract(ts2).Duration();
                statusLabel.Text = String.Format("{0} : {1}",ts.Minutes ,ts.Seconds);
            }
            else
            {
                _timer.Stop();
                _timer.Enabled = false;
            }
        }

        private void toolBtnSave_Click(object sender, EventArgs e)
        {
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.FileName = "result.bmp";
            if (DialogResult.OK == dialog.ShowDialog())
            {
                _searchPath.SaveFile(dialog.FileName);
            }
        }

    }
}

MainForm.Designer.cs

namespace Maze
{
    partial class MainForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.toolStrip1 = new System.Windows.Forms.ToolStrip();
            this.toolBtnStart = new System.Windows.Forms.ToolStripButton();
            this.toolBtnSave = new System.Windows.Forms.ToolStripButton();
            this.statusStrip1 = new System.Windows.Forms.StatusStrip();
            this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel();
            this.picBox = new System.Windows.Forms.PictureBox();
            this.toolStrip1.SuspendLayout();
            this.statusStrip1.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.picBox)).BeginInit();
            this.SuspendLayout();
            //
            // toolStrip1
            //
            this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.toolBtnStart,
            this.toolBtnSave});
            this.toolStrip1.Location = new System.Drawing.Point(0, 0);
            this.toolStrip1.Name = "toolStrip1";
            this.toolStrip1.Size = new System.Drawing.Size(635, 25);
            this.toolStrip1.TabIndex = 4;
            this.toolStrip1.Text = "toolStrip1";
            //
            // toolBtnStart
            //
            this.toolBtnStart.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
            this.toolBtnStart.Image = global::Maze.Properties.Resources.Start;
            this.toolBtnStart.ImageTransparentColor = System.Drawing.Color.Magenta;
            this.toolBtnStart.Name = "toolBtnStart";
            this.toolBtnStart.Size = new System.Drawing.Size(23, 22);
            this.toolBtnStart.Text = "Start";
            this.toolBtnStart.Click += new System.EventHandler(this.toolBtnStart_Click);
            //
            // toolBtnSave
            //
            this.toolBtnSave.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
            this.toolBtnSave.Image = global::Maze.Properties.Resources.Save;
            this.toolBtnSave.ImageTransparentColor = System.Drawing.Color.Magenta;
            this.toolBtnSave.Name = "toolBtnSave";
            this.toolBtnSave.Size = new System.Drawing.Size(23, 22);
            this.toolBtnSave.Text = "Save";
            this.toolBtnSave.Click += new System.EventHandler(this.toolBtnSave_Click);
            //
            // statusStrip1
            //
            this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.statusLabel});
            this.statusStrip1.Location = new System.Drawing.Point(0, 440);
            this.statusStrip1.Name = "statusStrip1";
            this.statusStrip1.Size = new System.Drawing.Size(635, 22);
            this.statusStrip1.TabIndex = 5;
            this.statusStrip1.Text = "statusStrip1";
            //
            // statusLabel
            //
            this.statusLabel.Name = "statusLabel";
            this.statusLabel.Size = new System.Drawing.Size(0, 17);
            //
            // picBox
            //
            this.picBox.Image = global::Maze.Properties.Resources.input;
            this.picBox.Location = new System.Drawing.Point(0, 26);
            this.picBox.Name = "picBox";
            this.picBox.Size = new System.Drawing.Size(635, 421);
            this.picBox.TabIndex = 2;
            this.picBox.TabStop = false;
            //
            // MainForm
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(635, 462);
            this.Controls.Add(this.statusStrip1);
            this.Controls.Add(this.toolStrip1);
            this.Controls.Add(this.picBox);
            this.Name = "MainForm";
            this.Text = "Maze";
            this.toolStrip1.ResumeLayout(false);
            this.toolStrip1.PerformLayout();
            this.statusStrip1.ResumeLayout(false);
            this.statusStrip1.PerformLayout();
            ((System.ComponentModel.ISupportInitialize)(this.picBox)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.PictureBox picBox;
        private System.Windows.Forms.ToolStrip toolStrip1;
        private System.Windows.Forms.ToolStripButton toolBtnSave;
        private System.Windows.Forms.StatusStrip statusStrip1;
        private System.Windows.Forms.ToolStripStatusLabel statusLabel;
        private System.Windows.Forms.ToolStripButton toolBtnStart;
    }
}

SearchPath.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

namespace Maze
{
    class SearchPath : ISearchPath
    {
        Stack<StackItem> _stack = new Stack<StackItem>();
        FootMarkTable _fmt = new FootMarkTable();
        PictureBox _picBox;
        Bitmap _image;
        Point _start;
        Point _end;
        Color _pathColor = Color.Red;
        public Color PathColor
        {
            set
            {
                _pathColor = value;
            }
        }

        private SearchPath()
        { }

        public SearchPath(PictureBox picBox, Point start, Point end)
        {
            _picBox = picBox;
            _image = new Bitmap(picBox.Image);
            _start = start;
            _end = end;
        }

        public void GetPath()
        {
            _isEnd = false;
            StackItem stackItem = InitStackItem();
            do
            {
                stackItem = ChangeDir(stackItem);
                if (!isWall(stackItem.curPos) && !_fmt.isFootMark(stackItem.curPos))
                {
                    ChangeLastItemDir(stackItem.dir);
                    stackItem.order++;
                    _stack.Push(stackItem); //入栈                  
                    _fmt.isFootMark(stackItem.curPos);//标记已经走过
                    if (stackItem.curPos.X == _end.X && stackItem.curPos.Y == _end.Y)
                    {//到达终点退出
                        break;
                    }
                    stackItem.dir = 1;
                    ChangePointColor(stackItem.curPos, _pathColor);
                }
                else
                {
                    if (stackItem.dir == 4)
                    {
                        stackItem = PopLastItem();
                    }
                    else
                    {
                        if (isWall(stackItem.curPos) || _fmt.isFootMark(stackItem.curPos))
                        {
                            stackItem = Untread(stackItem);
                            stackItem.dir++;
                        }
                    }
                }

            }
            while (_stack.Count > 0);

            _picBox.Image = _image;

            //清空栈
            _stack.Clear();
            _isEnd = true;
        }

        private bool isInBoundary(Point p)
        {
            return p.X >= _end.X && p.X <= _start.X;
        }

        /// <summary>
        /// 栈顶元素出栈
        /// </summary>
        /// <returns></returns>
        private StackItem PopLastItem()
        {
            StackItem stackItem = new StackItem();
            if (_stack.Count > 0)
            {
                ChangePointColor(((StackItem)_stack.Pop()).curPos, Color.White);
            }
            if (_stack.Count > 0)
            {
                StackItem stackItemTemp = (StackItem)_stack.Pop();
                stackItem.dir = stackItemTemp.dir;
                stackItem.order = stackItemTemp.order;
                stackItem.curPos.X = stackItemTemp.curPos.X;
                stackItem.curPos.Y = stackItemTemp.curPos.Y;
                if (stackItem.dir != 4)
                {
                    stackItem.dir++;
                }
                _stack.Push(stackItem);
            }
            return stackItem;
        }

        private StackItem InitStackItem()
        {
            StackItem stackItem = new StackItem();
            stackItem.curPos = _start;
            stackItem.order = 0;
            stackItem.dir = 0;
            return stackItem;
        }

        /// <summary>
        /// 退回前一个坐标
        /// </summary>
        /// <param name="stackItem"></param>
        /// <returns></returns>
        protected virtual StackItem Untread(StackItem stackItem)
        {
            switch (stackItem.dir)
            {
                case 1:
                    stackItem.curPos.X = stackItem.curPos.X + 1;
                    break;
                case 2:
                    stackItem.curPos.Y = stackItem.curPos.Y + 1;
                    break;
                case 3:
                    stackItem.curPos.Y = stackItem.curPos.Y - 1;
                    break;
                default:
                    break;
            }
            return stackItem;
        }

        /// <summary>
        /// 修改坐标的颜色
        /// </summary>
        /// <param name="p"></param>
        /// <param name="c"></param>
        /// <returns></returns>
        private Point ChangePointColor(Point p, Color c)
        {
            _image.SetPixel(p.X, p.Y, c);
            //_picBox.Image = _image;
            return p;
        }

        /// <summary>
        /// 修改上一坐标的方向
        /// </summary>
        /// <param name="tmpDir"></param>
        private void ChangeLastItemDir(int tmpDir)
        {
            if (_stack.Count > 0)
            {
                StackItem stackItemTemp = (StackItem)_stack.Pop();
                stackItemTemp.dir = tmpDir;
                _stack.Push(stackItemTemp);
            }
        }

        protected virtual StackItem ChangeDir(StackItem stackItem)
        {
            switch (stackItem.dir)
            {
                case 1://向左
                    stackItem.curPos.X = stackItem.curPos.X - 1;
                    break;
                case 2://向上
                    stackItem.curPos.Y = stackItem.curPos.Y - 1;
                    break;
                case 3://向下
                    stackItem.curPos.Y = stackItem.curPos.Y + 1;
                    break;
                case 4://向右
                    stackItem.curPos.X = stackItem.curPos.X + 1;
                    break;
                case 0:
                    stackItem.dir = 1;
                    break;
                default:
                    break;
            }
            return stackItem;
        }

        /// <summary>
        /// 判断是否是墙
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        private bool isWall(Point p)
        {
            Color c = _image.GetPixel(p.X, p.Y);           
            return c.A == Color.Black.A && c.B == Color.Black.B && c.G == Color.Black.G && c.R == Color.Black.R;
        }

        public void SaveFile(string fileName)
        {
            _image.Save(fileName);
        }

        private bool _isEnd = true;
        public bool IsEnd
        {
            get { return _isEnd; }
        }

    }

    public struct StackItem
    {
        public int order;
        public int dir;
        public Point curPos;
    }
}

Program.cs

using System.Collections.Generic;
using System.Windows.Forms;

namespace Maze
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    }
}

 

如下图是我得出的结果:

result
源码