2009年9月刊《程序员》算法题之我见——思索之三
2009-10-08 20:53
330 查看
本系列文章目录
2009年9月刊《程序员》算法题之我见——思索之一
2009年9月刊《程序员》算法题之我见——思索之二
2009年9月刊《程序员》算法题之我见——思索之三
接上文“2009年9月刊《程序员》算法题之我见——思索之二”
仔细分析后发现,似乎不能推导出一个统一的公式来计算出大于三行的可能数。只能另辟蹊径。
问题七:M=15,N=2,P=S,求方案总数
这个问题现在的解决方法如下
第一步:先得到每一行P=2S的方案数以及每一个方案
第二步:将每一个方案一拆二,分为S和S。这表示这两个方案使能够相邻的,将相邻的可能压入一个表,用来备用。这一步的理由参看上一篇文章。
第三步:初始化第一行的每一种可能,每一种的可能都计数为1。从第二行开始,通过查表,得知上一行的每一个方案在这一行的相邻方案是什么,然后计数。随着行数的增多,每种方案在每一行出现的可能数都会发生变化。
第四步:到最后一行,统计最后一行每一种方案的各自可能数。然后求总和。
经过测试,M=15,N=150,P=4的解为70种,和之前的问题五的答案一致。当M=15,N=4,P=2的解出乎我的意料,为3328134种。不知其他人的答案是否和我的一致,欢迎交流。
下面详细分析每一步,并贴代码,用的是VB2005
函数
Public Function CacuInternSiteCount(ByVal Line As Integer, ByVal SitePerLine As Integer, ByVal InternPerLine As Integer) As Integer
Line表示行数
SitePerLine表示每一排的座位数
InternPerLine表示每一排的实习生数
返回方案总数
先是变量定义:
都是临时变量,后面再详细介绍。
预备步:
在后面的第二步计算中,要将每一个方案一拆二。而一拆二的依据就是利用组合原理,从2S中选出S的组合来,这个利用的组合函数,以及获得组合的方法在详细可以参见“遍历组合的实现——VB2005”和“遍历排列的实现——VB2005”这两篇文章。
第一步:先得到每一行P=2S的方案数以及每一个方案。这里得到的每一个方案也是调用组合函数。得到一个组合再判断这个组合是否符合题目的要求,用的是IsOk这个函数。
第二步:将每一个方案一拆二,分为S和S。这表示这两个方案使能够相邻的,将相邻的可能压入一个表,用来备用。
这里调用了IsOk函数,这是判断实习生的位置是否符合题目的要求,代码如下:
还有一个注意的地方,很多人以为VB2005是没有移位运算的,可其实是有的。这里的S1就是2S的一个组合,然后拆分为S2和S3的S的组合。
第三步:初始化第一行的每一种可能,每一种的可能都计数为1。从第二行开始,通过查表,得知上一行的每一个方案在这一行的相邻方案是什么,然后计数。随着行数的增多,每种方案在没一行出现的可能数都会发生变化。
最后一步统计:统计每一种情况出现的可能数,求总和,并返回。
最后将上述所有代码一起贴下来。也欢迎大家交流。
2009年9月刊《程序员》算法题之我见——思索之一
2009年9月刊《程序员》算法题之我见——思索之二
2009年9月刊《程序员》算法题之我见——思索之三
接上文“2009年9月刊《程序员》算法题之我见——思索之二”
仔细分析后发现,似乎不能推导出一个统一的公式来计算出大于三行的可能数。只能另辟蹊径。
问题七:M=15,N=2,P=S,求方案总数
这个问题现在的解决方法如下
第一步:先得到每一行P=2S的方案数以及每一个方案
第二步:将每一个方案一拆二,分为S和S。这表示这两个方案使能够相邻的,将相邻的可能压入一个表,用来备用。这一步的理由参看上一篇文章。
第三步:初始化第一行的每一种可能,每一种的可能都计数为1。从第二行开始,通过查表,得知上一行的每一个方案在这一行的相邻方案是什么,然后计数。随着行数的增多,每种方案在每一行出现的可能数都会发生变化。
第四步:到最后一行,统计最后一行每一种方案的各自可能数。然后求总和。
经过测试,M=15,N=150,P=4的解为70种,和之前的问题五的答案一致。当M=15,N=4,P=2的解出乎我的意料,为3328134种。不知其他人的答案是否和我的一致,欢迎交流。
下面详细分析每一步,并贴代码,用的是VB2005
函数
Public Function CacuInternSiteCount(ByVal Line As Integer, ByVal SitePerLine As Integer, ByVal InternPerLine As Integer) As Integer
Line表示行数
SitePerLine表示每一排的座位数
InternPerLine表示每一排的实习生数
返回方案总数
先是变量定义:
Dim i As Integer, j As Integer Dim tP() As Integer, tP1() As Integer Dim tL As New List(Of Array) Dim S1 As Integer, S2 As Integer, S3 As Integer Dim tMap As New clsInternMap Dim tF As New Dictionary(Of Integer, Integer) Dim tF2 As New Dictionary(Of Integer, Integer)
都是临时变量,后面再详细介绍。
预备步:
For i = 0 To clsCombination.C(InternPerLine, 2 * InternPerLine) - 1 tP1 = clsCombination.GetCombination(0, 2 * InternPerLine - 1, InternPerLine, i) tL.Add(tP1) Next
在后面的第二步计算中,要将每一个方案一拆二。而一拆二的依据就是利用组合原理,从2S中选出S的组合来,这个利用的组合函数,以及获得组合的方法在详细可以参见“遍历组合的实现——VB2005”和“遍历排列的实现——VB2005”这两篇文章。
第一步:先得到每一行P=2S的方案数以及每一个方案。这里得到的每一个方案也是调用组合函数。得到一个组合再判断这个组合是否符合题目的要求,用的是IsOk这个函数。
第二步:将每一个方案一拆二,分为S和S。这表示这两个方案使能够相邻的,将相邻的可能压入一个表,用来备用。
For i = 0 To clsCombination.C(2 * InternPerLine, SitePerLine) - 1 tP = clsCombination.GetCombination(0, SitePerLine - 1, 2 * InternPerLine, i) If IsOk(tP) = True Then S1 = 0 For j = 0 To tP.GetUpperBound(0) S1 = S1 Or (1 << tP(j)) Next For Each tP1 In tL S2 = 0 For j = 0 To tP1.GetUpperBound(0) S2 = S2 Or (1 << tP(tP1(j))) Next S3 = S1 - S2 tMap.Add(S2, S3) Next End If Next
这里调用了IsOk函数,这是判断实习生的位置是否符合题目的要求,代码如下:
Public Function IsOk(ByVal tP() As Integer) As Integer Dim tB As Boolean = False For i = 1 To tP.GetUpperBound(0) If tP(i) - tP(i - 1) < 2 Then Return False End If Next Return True End Function
还有一个注意的地方,很多人以为VB2005是没有移位运算的,可其实是有的。这里的S1就是2S的一个组合,然后拆分为S2和S3的S的组合。
第三步:初始化第一行的每一种可能,每一种的可能都计数为1。从第二行开始,通过查表,得知上一行的每一个方案在这一行的相邻方案是什么,然后计数。随着行数的增多,每种方案在没一行出现的可能数都会发生变化。
For Each i In tMap.GetKeys tF.Add(i, 1) tF2.Add(i, 0) Next Dim tL2 As List(Of Integer), k As Integer, tL3 As New List(Of Integer) tL3.AddRange(tF.Keys) For i = 2 To Line For Each j In tL3 tL2 = tMap.GetIndex(j) If Not (tL2 Is Nothing) Then For Each k In tL2 tF2(k) = tF2(k) + tF(k) Next End If Next For Each j In tL3 tF(j) = tF2(j) tF2(j) = 0 Next j Next
最后一步统计:统计每一种情况出现的可能数,求总和,并返回。
S1 = 0 For Each j In tL3 S1 += tF(j) Next Return S1
最后将上述所有代码一起贴下来。也欢迎大家交流。
Public Class clsIntern
Public Function CacuInternSiteCount(ByVal Line As Integer, ByVal SitePerLine As Integer, ByVal InternPerLine As Integer) As Integer
Dim i As Integer, j As Integer Dim tP() As Integer, tP1() As Integer Dim tL As New List(Of Array) Dim S1 As Integer, S2 As Integer, S3 As Integer Dim tMap As New clsInternMap Dim tF As New Dictionary(Of Integer, Integer) Dim tF2 As New Dictionary(Of Integer, Integer)
For i = 0 To clsCombination.C(InternPerLine, 2 * InternPerLine) - 1 tP1 = clsCombination.GetCombination(0, 2 * InternPerLine - 1, InternPerLine, i) tL.Add(tP1) Next
For i = 0 To clsCombination.C(2 * InternPerLine, SitePerLine) - 1
tP = clsCombination.GetCombination(0, SitePerLine - 1, 2 * InternPerLine, i)
If IsOk(tP) = True Then
S1 = 0
For j = 0 To tP.GetUpperBound(0)
S1 = S1 Or (1 << tP(j))
Next
For Each tP1 In tL
S2 = 0
For j = 0 To tP1.GetUpperBound(0)
S2 = S2 Or (1 << tP(tP1(j)))
Next
S3 = S1 - S2
tMap.Add(S2, S3)
Next
End If
Next
For Each i In tMap.GetKeys
tF.Add(i, 1)
tF2.Add(i, 0)
Next
Dim tL2 As List(Of Integer), k As Integer, tL3 As New List(Of Integer)
tL3.AddRange(tF.Keys)
For i = 2 To Line
For Each j In tL3
tL2 = tMap.GetIndex(j)
If Not (tL2 Is Nothing) Then
For Each k In tL2
tF2(k) = tF2(k) + tF(k)
Next
End If
Next
For Each j In tL3
tF(j) = tF2(j)
tF2(j) = 0
Next j
Next
S1 = 0
For Each j In tL3
S1 += tF(j)
Next
Return S1
End Function
Public Function IsOk(ByVal tP() As Integer) As Integer
Dim tB As Boolean = False
For i = 1 To tP.GetUpperBound(0)
If tP(i) - tP(i - 1) < 2 Then
Return False
End If
Next
Return True
End Function
End Class
Public Class clsInternMap
Private mMap As Dictionary(Of Integer, List(Of Integer))
Public Sub New()
mMap = New Dictionary(Of Integer, List(Of Integer))
End Sub
Public Sub Add(ByVal S1 As Integer, ByVal S2 As Integer)
If mMap.ContainsKey(S1) = True Then
If mMap(S1).Contains(S2) = False Then
mMap(S1).Add(S2)
End If
Else
mMap.Add(S1, New List(Of Integer))
mMap(S1).Add(S2)
End If
End Sub
Public Function GetIndex(ByVal S1 As Integer) As List(Of Integer)
If mMap.ContainsKey(S1) = True Then
Return mMap(S1)
Else
Return Nothing
End If
End Function
Public Function GetKeys() As List(Of Integer)
Dim tL As New List(Of Integer)
tL.AddRange(mMap.Keys)
Return tL
End Function
End Class
相关文章推荐
- 2009年9月刊《程序员》算法题之我见——思索之一
- 2009年9月刊《程序员》算法题之我见——思索之二
- 测测您的能力:微软程序员测试题(算法)
- 【算法设计与数据结构】为何程序员喜欢将INF设置为0x3f3f3f3f?
- 程序员面试题精选100题(03)-子数组的最大和[算法]
- 程序员的算法趣题Perl版(四)
- 程序员必须知道的10大基础实用算法及其讲解
- 博客园电子期刊2009年10月刊发布啦
- 算法是内功,程序员别冷落算法!
- 寒假挑战PythonTip(一人一python)总结——算法是程序的灵魂,程序员的心法
- 程序员面试题精选100题(63)-数组中三个只出现一次的数字[算法]
- 程序员如何快速准备面试中的算法
- 程序员应该熟练掌握这些算法
- 如何思索算法(三)-动态规划
- 程序员懂算法玩“淮安掼蛋”是否更有优势?
- 程序员必须知道的10大基础实用算法及其讲解
- 程序员面试题精选100题(29)-调整数组顺序使奇数位于偶数前面[算法]
- 程序员必知的10大基础实用性算法
- 程序员必须知道的10大基础实用算法及其讲解
- 程序员一定要了解哪十大算法