偶尔要写写算法,是我平时用来保持感觉的常用的方法.今天看到园子里一面试题,看了一下感觉也能实现,不过过程确实艰的,自认为自己对算法的感觉还不错.不过这题确实我也用了差不多一下午的时间,基本上把工作时间都耗掉了.主要的两个方法已经搞定,下面先说一下思想,代码确实不太重要,因为过一周我自己就会看不懂了,就像我今天也去看以前的代码.因为这里用到一部分深度优先遍历,所以去找以前代码,但是完全没有作用,还是纯写.

  

    interface IPath
{
/// <summary>
/// 增加某条地铁线路
/// </summary>
/// <param name="lineNo">地铁线号</param>
/// <param name="stationNum">站点数目</param>
/// <param name="stationArray">地铁线站台号数组</param>
void AddLine(int lineNo, int stationNum, int[] stationArray); /// <summary>
/// 计算从超点到终点的最短路线长度
/// </summary>
/// <param name="srcStation">起点站</param>
/// <param name="desStation">终点站</param>
/// <returns>起点站到终点站最短线长度</returns>
int CalcMinPathLen(int srcStation, int desStation); /// <summary>
/// 输出从起点到终点的最短路线
/// </summary>
/// <param name="srcStation">起点</param>
/// <param name="desStation">终点</param>
/// <param name="pathNum">条数</param>
/// <param name="pathLen">长度</param>
/// <param name="pathes">结果路线集合</param>
/// <returns>0成功 -1出错</returns>
int SearchMinPaths(int srcStation, int desStation, out int pathNum, out int pathLen, out int[][] pathes); /// <summary>
/// 最优路线
/// </summary>
/// <param name="srcStation">起点</param>
/// <param name="desStation">终点</param>
/// <param name="pathNum">条数</param>
/// <param name="pathLen">长度</param>
/// <param name="pathes">结果路线集合</param>
/// <returns>0成功 -1出错</returns>
int SearchBestPathes(int srcStation, int desStation, out int pathNum, out int pathLen, out int[][] pathes); }

其实这个从题目中命名等看出来主要是C++题,本人用C#实现,其实可以改一些参数名称更为方便,但是这里就按题目中接口来吧.AddLine方法就不说了.

int CalcMinPathLen(int srcStation, int desStation);

计算最短路径,这里用的是迪杰斯特拉算法,就是从起点按起点到各各点最短距离来一个一个往集合里面添加,当然这里的距离就是1,如果是其它数字也是可以的.

int SearchMinPaths(int srcStation, int desStation, out int pathNum, out int pathLen, out int[][] pathes);

这个方法其实略坑了,我基本上是重新想的解决办法,同第一个方法没有很大的联系,不知道我这种思考是否是最优的,不过是可以解决的.重点地方就是用到一个变异的深度优先遍历,这个是有环路存在的,所以比树的深度优先遍历要复杂一些,注意一下深度就可以了,用到一个深度变量去控制是不是保留在遍历排除集合中,就是方法中的list.

两个方法代码如下

    public class MetroPath : IPath
{
private readonly List<Tuple<int, int, int[]>> pathes;
private int stationCount = ; private List<int> minStations; public MetroPath()
{
pathes = new List<Tuple<int, int, int[]>>();
minStations = new List<int>();
} public void AddLine(int lineNo, int stationNum, int[] stationArray)
{
if (stationNum < || stationArray == null || stationArray.Length != stationNum)
Console.WriteLine("站点数目不对");
else
pathes.Add(new Tuple<int, int, int[]>(lineNo, stationNum, stationArray));
} public int CalcMinPathLen(int srcStation, int desStation)
{
//用迪杰斯特拉算法计算
Dictionary<int, int> stationLens = new Dictionary<int, int>(); IEnumerable<int> ct = pathes[].Item3;
//得到所有站数
foreach (var a in pathes)
{
ct = ct.Union(a.Item3);
}
stationCount = ct.Distinct().Count(); try
{
stationLens.Add(srcStation, );//初始 while (stationLens.Count < stationCount)
{
stationLens = FindMinStation(stationLens, srcStation);
} //下一题用
minStations = stationLens.Select(x => x.Key).ToList(); //找出起点到终点最短长度
return stationLens[desStation];
}
catch
{
return -; //出错
}
} //找出余下站点中最短的站点及起点到它的长度
private Dictionary<int, int> FindMinStation(Dictionary<int, int> stations, int srcStation)
{
Dictionary<int, int> lens = new Dictionary<int, int>(); foreach (var p in pathes)
{
foreach (var station in p.Item3)
{
if (!stations.ContainsKey(station))
{
//计算最小值
var minlen = ReachLen(stations, srcStation, station);
if (minlen > && !lens.ContainsKey(station))
lens.Add(station, minlen);
}
}
} //找出lens中最小的(可以多个)加入集合
int min = lens.Min(v => v.Value); return stations.Union(lens.Where(x => x.Value == min)).ToDictionary(k => k.Key, v => v.Value);
} //是否是可达的 -1为不可达
private int ReachLen(Dictionary<int, int> stations, int srcStatoin, int station)
{
List<int> reachStations = new List<int>();
foreach (var p in pathes)
{
for (int i = ; i < p.Item3.Length; i++)
{
if (p.Item3[i] == station)
{
if (i - >= && !reachStations.Contains(p.Item3[i - ]))
reachStations.Add(p.Item3[i - ]);
if (i + < p.Item3.Length && !reachStations.Contains(p.Item3[i + ]))
reachStations.Add(p.Item3[i + ]);
}
}
} var q = stations.Where(v => reachStations.Contains(v.Key));
//相邻点不在集合里面
if (q == null || q.Count() <= )
return -;
else
{
//找出q中最小的值
return q.OrderByDescending(v => v.Value).First().Value + ;
} } public int SearchMinPaths(int srcStation, int desStation, out int pathNum, out int pathLen, out int[][] pathes)
{
pathNum = ;
pathLen = ;
pathes = null; try
{
pathLen = CalcMinPathLen(srcStation, desStation); List<int[]> result = new List<int[]>(); Stack<int> sk1 = new Stack<int>();
List<Tuple<int, int>> list = new List<Tuple<int, int>>(); sk1.Push(srcStation);
minStations.Remove(srcStation); int ct = ;
int deepth = ;
while (deepth > )
{
bool flag = false;
foreach (var x in minStations)
{
list.RemoveAll(v => v.Item1 > deepth); if (ExistsRalation(sk1.Peek(), x) && !sk1.Contains(x) && list.Where(v => v.Item2 == x).Count() <= )
{
sk1.Push(x);
deepth++;
flag = true;
break;
}
} //
if (sk1.Peek() == desStation)
{
//一条完整的路线
result.Add(sk1.Reverse().ToArray());
deepth--;
list.Add(new Tuple<int, int>(deepth, sk1.Pop()));
ct++;
}
//没有找到
if (!flag)
{
deepth--;
list.Add(new Tuple<int, int>(deepth, sk1.Pop()));
}
} pathNum = ct;
pathes = result.ToArray();
return ;
}
catch
{
return -;
} } private bool ExistsRalation(int a, int b)
{
if (a == b)
return false; foreach (var p in pathes.Where(x => x.Item3.Contains(a) && x.Item3.Contains(b)))
{
for (int i = ; i < p.Item3.Length; i++)
{
if (p.Item3[i] == a)
{
if (i - >= && p.Item3[i - ] == b)
return true;
if (i + < p.Item3.Length && p.Item3[i + ] == b)
return true;
}
}
}
return false; } public int SearchBestPathes(int srcStation, int desStation, out int pathNum, out int pathLen, out int[][] pathes)
{
throw new NotImplementedException();
}
}

最后一个方法还没有实现,不过大思路也还是可以有的,路径找出来了,只要看路径上交乘点多少就可以了,越少越优,这个算简单.没有时间写了.

最后是调用代码和结果

            //测试
IPath mp = new MetroPath();
mp.AddLine(, , new int[] { , , , , });
mp.AddLine(, , new int[] { , , , , });
mp.AddLine(, , new int[] { , , });
mp.AddLine(, , new int[] { , }); var min = mp.CalcMinPathLen(, );
Console.WriteLine("从1到11最短路径长度为:{0}", min); int pathNum = ;
int pathLen = ;
int[][] pathes = null;
var re = mp.SearchMinPaths(, , out pathNum, out pathLen, out pathes); Console.WriteLine("从1到11最短路径条数为{0},分别是", pathNum);
foreach (var x in pathes)
{
Console.Write("\n{");
foreach (var i in x)
{
Console.Write("{0},", i);
}
Console.Write("}\n");
} Console.ReadLine();

对题中的数据来看是正常的.个人觉得本题还是有难度的,特别是要实实在在写出来,并且调通,我看文中评论有些说简单的人请去实践一下再说吧.

插个小插曲,就是代码一写过基本上就看不懂了.刚才我说到我查阅深度优先算法,我自己的代码完全看不懂,不过看起来以前写的还是很简练,不过是对简单图的遍历.

        /// <summary>
/// 深度优先
/// </summary>
static void DFS(int[,] a, int n)
{
Stack<int> sk1 = new Stack<int>();
Stack<int> sk2 = new Stack<int>();
sk1.Push();
Console.WriteLine();
int x = ;//访问点标记 int ct = ;//访问节点数
while (ct < n)
{
int i = ;
bool f = false;
for (i = ; i < n; i++)
{
if (a[x, i] != && !sk2.Contains(i))
{
sk1.Push(i);
Console.WriteLine(i); ct++;
x = i; f = true;
break;
}
}
if (!f)
{
//没有找到返回
sk2.Push(sk1.Pop());
x = sk1.Peek();
} }
}

确实比较短的,不过看不懂.所以主要还是在于思想吧.数据测试

            int[,] a = {
{,,,,}
,{,,,,}
,{,,,,}
,{,,,,}
,{,,,,}
}; Console.WriteLine("DFS:");
DFS(a, );
Console.Read();

  最后总结:  

    1.理解迪杰斯特拉算法

    2.深度优先遍历,主要用栈,广度优先主要考虑队列.

    3.深度优先的冲突处理,考虑用深度变量.

<<薪资至少10K的一道题,你能拿下吗>>练习的更多相关文章

  1. 薪资至少10K的一道题,你能拿下吗

    我所了解的华为: 应届本科生8k+ 应届硕士生10k+ 应届博士生12k+ 看到后什么感想?有没有只恨生不逢时运不佳的感觉? 很多人做3年多甚至更久,才能达到这个薪资水平,还不如一个新生. 在我看来, ...

  2. 盘点一下Github上开源的Java面试/学习相关的仓库,看完弄懂薪资至少增加10k

    最近浏览 Github ,收藏了一些还算不错的 Java面试/学习相关的仓库,分享给大家,希望对你有帮助.我暂且按照目前的 Star 数量来排序. 本文由 SnailClimb 整理,如需转载请联系作 ...

  3. 深圳--博雅互动 Android面试打酱油归来

    公司在TCL工业园E4,坐地到西丽站,那边在修路,不好走.B796公交站台在A出口的反方向,还要顺着施工的屏障打个弯,在西丽法院1上车.公司那边比较偏了,附近只有两趟公交.办公地点在10楼,出电梯就可 ...

  4. IOS培训还值得么

    文章结构 1培训机构 各方面的评价 培训安排 收获 2 市场 就业 是否饱和 3 姿势 做好的事情 IOS这几年在IT界一直是热门的讨论话题,之前看着拉钩出品的北上广高薪岗位的人员技术流动也主要指向这 ...

  5. 我是如何自学 Python 的

    不少初学 Python 或者准备学习 Python 的小伙伴问我如何学习 Python.今天就说说我当时是怎么学习的. 缘起 我大学专业是电气工程,毕业后做的是自动化方面的工作.对于高级语言编程基本是 ...

  6. 小白数据分析——Python职位全链路分析

    最近在做Python职位分析的项目,做这件事的背景是因为接触Python这么久,还没有对Python职位有一个全貌的了解.所以想通过本次分析了解Python相关的职位有哪些.在不同城市的需求量有何差异 ...

  7. 阶段总结-Java基础-超进阶

    Gitee项目地址:https://gitee.com/zc10010/java_interview_guide/tree/master/知识点话术 项目叫话术,但是我觉得作为知识点学习是挺不错的. ...

  8. 【poj2151】 Check the difficulty of problems

    http://poj.org/problem?id=2151 (题目链接) 题意 T支队伍,一共M道题,第i支队伍解出第j道题的概率为p[i][j].问每支队伍至少解出1道题并且解题最多的的队伍至少解 ...

  9. XidianOJ 1020 ACMer去刷题吧

    题目描述 刷题是每个ACMer必由之路,已知某oj上有n个题目,第i个题目小X能做对的概率为Pi(0<=Pi<=1,1<=i<=n) 求小X至少做对k道题的概率 输入 第一行输 ...

随机推荐

  1. ServiceStack.OrmLite 6 学习笔记 查

    查 根据id var result = db.SingleById<Poco>(1); 根据字段 var customer = db.Single<Customer>(new ...

  2. Zookeeper相关知识

    一.Zookeeper是什么? Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务.状态同步服务. ...

  3. 数据库mysql中having 和where的区别

    having的用法 having字句可以让我们筛选成组后的各种数据,where字句在聚合前先筛选记录,也就是说作用在group by和having字句前.而 having子句在聚合后对组记录进行筛选. ...

  4. XML命名空间详解

    http://happylongnv.blog.hexun.com/48859954_d.html 目的:解决同一个元素在相同文件中代表不同含义的问题.因为XML文档中使用的元素不是固定的,那么两个不 ...

  5. Jquery中css()方法获取边框长度

    1. JQuery中可以使用css()方法获取块元素的边框宽度,如下: $("divMode").css("border-left-width");//左边框长 ...

  6. 一些比较好的shellscript脚本

    1. 变量与替换 #!/bin/bash # 变量替换 # 另外, 变量替换还有许多别的语法 # 例如, b=${a/23/bb} 将 23 替换成 bb 等等, 用到时再找 a=375 hello= ...

  7. 有趣的JavaScript小程序

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. go语言中间的循环

    在Go语言中只有很少的几个控制结构,它没有while或者do-while循环. 但是它有for.switch.if.而且switch接受像for那样可选的初始化语句.下面来认识一下他们 一.if语句 ...

  9. [CSS] vertical-align

    原文地址: http://www.zhangxinxu.com/wordpress/2010/05/%E6%88%91%E5%AF%B9css-vertical-align%E7%9A%84%E4%B ...

  10. Winform_ComBox三种赋值方式

    第一种方法: DataTable dt = new DataTable(); dt.Columns.Add( "name" ); dt.Columns.Add( "val ...