我有一个包含许多菜单的WinForms应用程序,每个菜单平均有30个菜单项。在任何给定的菜单中,可以有多个以相同字母开头的单词。
目前,我使用一种简单的方法,通过在每个菜单项的前面添加一个&符号来创建每个项目的alt键映射。
我需要能够检测到重复的键映射(起始字母)并将其重新分配给另一个字符;尚未采取行动。获胜的角色将是最接近该词乞讨的角色。
更理想的算法足够聪明,可以查看字符串中的下一个单词,并具有附加规则。如果我可以创建一组模拟菜单的规则,例如:
我知道火狐最有可能手动分配他们的映射 - 但我试图建设性地懒惰。
答案 0 :(得分:4)
您可以将此视为http://en.wikipedia.org/wiki/Hungarian_algorithm的示例。在文章的语言中,将您的菜单项标题视为工作人员。您希望将每个工作人员分配到一个工作,其中一个工作是来自A-Z的一封信。将工作人员分配给字母(作业)的成本是菜单项中该字母的索引。这最小化了索引的总和,因此如果第一个字母都不同,最好的解决方案是使用每个菜单项的第一个字母。
当然,您通常会有比菜单项更多的字母。你可以通过发明虚拟菜单项来解决这个问题,为每个可能的字母菜单项分配收取相同的金额。
答案 1 :(得分:1)
由于您平均有30个项目,因此总是会使用多次使用的加速器字母。并且你肯定不希望一个项目的字母改变你的程序的多次运行(或者更糟糕的是,在同一次运行中使用多个菜单)。
为什么不保持简单并要求每个菜单项都有一个静态的“加速器字母”属性?
答案 2 :(得分:0)
对于不耐烦的人,像我一样,在C#here中有一个非常干净的匈牙利算法实现,这里有一个快速的测试平台来解决OP的问题:
Module Module1
Sub Main()
test1()
End Sub
Sub test1()
Dim menus() As String =
{"File",
"Fiddle",
"Forest",
"Fangle",
"Edit",
"Entity",
"Entropy",
"Eviction",
"View",
"Vixen",
"Visible",
"Window",
"Wait",
"What",
"Tools",
"Time",
"Total",
"Tea"}
Dim items As Integer = menus.GetUpperBound(0)
Dim alphabet As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
Dim letters As Integer = alphabet.Length - 1
Dim costs(items, letters) As Integer
Dim cost As Integer
Dim ch As String
Dim o As Integer
Dim longest As Integer = 0
For i = 0 To items
cost = 1
If menus(i).Length > longest Then
longest = menus(i).Length
End If
For j = 0 To menus(i).Length - 1
ch = menus(i).Substring(j, 1)
o = alphabet.IndexOf(ch, StringComparison.InvariantCultureIgnoreCase)
If costs(i, o) = 0 Then ' Don't overwrite when same letter more than once in word
costs(i, o) = cost
cost += 2
End If
Next
For j = 0 To letters
If costs(i, j) = 0 Then
costs(i, j) = 99
End If
Next
Next
longest += 1
For r = 1 To 2
Console.Write("".PadRight(longest))
For i = 0 To letters
Console.Write(alphabet.Substring(i, 1).PadLeft(3))
Next
Console.WriteLine("")
For i = 0 To items
Console.Write(menus(i).PadRight(longest))
For j = 0 To letters
Console.Write(costs(i, j).ToString.PadLeft(3))
Next
Console.WriteLine("")
Next
If r = 1 Then
Dim h As New HungarianAlgorithm
Dim result() As Integer
result = h.FindAssignments(costs)
Console.WriteLine("Answer:")
For i = 0 To items
Console.WriteLine(menus(i).PadRight(longest) & alphabet.Substring(result(i), 1))
Next
End If
Next r
End Sub
结束模块