◆≈≈ 请教一个算法,有点刁 ≈≈◆

Fairphoenix 2009-12-02 12:09:35
目标需求:

  实现一函数 Function fun(M, K, N) As Long
  入口参数:M、K、N 都为整数。取值范围:
   M : 1 ~ 255
   K : 1 ~ 15
   N : 0 ~ 63


  返回值要在达到的条件:
假设返回值 Q 的十六进制形式为(高字节 <- -> 低字节):&H [HHa] [HHb] [HHc] [HHd]
         十进制形式为:nnnnn
返回值必须满足:
[HHd] = M 【相当于把 M 直接填到返回值的低字节】
[HHc] = (所有十进制数位的每位之和) * K + N
[HHa][HHb] 的值(返回值的高两字节整体)在 &H01 ~ &H7F 之间(含),由算法按需填入。


  注意:不要用“穷举法”(或类似穷举法)实现。
  对于一组确定的入口参数,可能有多个返回值符合要求,能返回任一个就行了。当然,能把所有的结果都返回则更好!



举个例子说:Rlt = fun(36, 1, 0)
则返回 Rlt = 201764   (十进制 201764 = &H00031424)
&H00031424 = 36   (M = 36 )
&H00031424 = 20   ( (2+0+1+7+6+4) * 1 + 0 = 20 )
...全文
1149 49 打赏 收藏 转发到动态 举报
写回复
用AI写文章
49 条回复
切换为时间正序
请发表友善的回复…
发表回复
舉杯邀明月 2010-01-10
  • 打赏
  • 举报
回复
小仙妹出马,肯定有所收获!

我刚才检查了一下 42F 的结果,都是正确的。


不知小仙妹用的什么算法?
能透露一下吗?

符合楼主要求的条件不?
舉杯邀明月 2010-01-10
  • 打赏
  • 举报
回复
估计穷举法也基本上只能这样了。
不知道楼主的代码写成什么啥模样的。



小仙妹的‘10进制校验和’中 为什么要用 tLoopIndex = 0 To 9 啊,这样pValue无论是多少都是10次循环吧?

我倒是这样写的,小仙妹可否点评一下:
tOutCheckSum = 0
while (pValue > 0)
tOutCheckSum = tOutCheckSum + pValue mod 10
pValue = pValue \ 10
wend
我当时考虑这个问题时,这段代码没有写成函数,直接写在穷举循环中。
觉得就这么点儿代码,也只有那里用它,写成函数没必要。
KiteGirl 2010-01-10
  • 打赏
  • 举报
回复
这是带注释的代码。


Function GetRlt2(ByVal pM As Byte, ByVal pK As Byte, ByVal pN As Byte) As Long
'返回能找到的第一个结果

Dim tOutValue As Long '输出值

Dim tCheckSum As Long '校验和(循环历遍值)

Dim tMixValue As Long '组合值

Dim tHBit As Long '高位值

For tHBit = 1 To &H7FFF '历遍高位值

For tCheckSum = 0 To 255 '历遍校验和

tMixValue = tHBit * &H10000 + tCheckSum * &H100 + pM '组合值

If CheckSum(tMixValue) * pK + pN = tCheckSum Then '如果组合值的实际校验和等于循环历遍到的校验和

tOutValue = tMixValue '输出组合值

tCheckSum = 255: tHBit = &H7FFF '跳出双循环

End If

Next

Next

GetRlt2 = tOutValue '返回输出值
End Function

Function GetRlt(ByVal pM As Byte, ByVal pK As Byte, ByVal pN As Byte) As Long()
'返回所有可能的结果。

Dim tOutValues() As Long '输出数组
Dim tOutValues_Index As Long '输出数组指针
Dim tOutValues_Length As Long '输出数组长度

Dim tCheckSum As Long '校验和

Dim tMixValue As Long '组合值

Dim tHBit As Long '高位值

tOutValues_Length = &HFF '初始数组长度255

ReDim tOutValues(tOutValues_Length)

For tHBit = 1 To &H7FFF '历遍高位值

For tCheckSum = 0 To 255 '历遍校验和

tMixValue = tHBit * &H10000 + tCheckSum * &H100 + pM '组合值

If CheckSum(tMixValue) * pK + pN = tCheckSum Then '如果组合值的实际校验和等于循环历遍到的校验和则将此结果推到结果集中。

'数组长度检查,如果长度不足以容纳结果,则增加255个元素。

If tOutValues_Index > tOutValues_Length Then

tOutValues_Length = tOutValues_Length + &HFF
ReDim Preserve tOutValues(tOutValues_Length)

End If

tOutValues(tOutValues_Index) = tMixValue '当前结果写入数组。

tOutValues_Index = tOutValues_Index + 1 '指针递增。

End If

Next

Next

'裁切数组,只保留有效长度。

tOutValues_Length = tOutValues_Index - 1
ReDim Preserve tOutValues(tOutValues_Length)

GetRlt = tOutValues()
End Function

Function CheckSum(ByVal pValue As Long) As Long
'返回10进制校验和
Dim tOutCheckSum As Long
Dim tLoopValue As Long
Dim tLoopIndex As Long

tLoopValue = pValue

For tLoopIndex = 0 To 9

tOutCheckSum = tOutCheckSum + tLoopValue Mod 10
tLoopValue = tLoopValue \ 10

Next

CheckSum = tOutCheckSum
End Function
KiteGirl 2010-01-10
  • 打赏
  • 举报
回复
从实用角度来说,1.9秒穷举出所有的结果还是能用的(不同组合大约在32768到11个结果之间)。如果只想要一个结果则速度更快。

但如果是算法课程的作业或者面试题,既然题意不允许穷举,那么上述算法是不行的。
KiteGirl 2010-01-10
  • 打赏
  • 举报
回复
[Quote=引用 43 楼 chen8013 的回复:]
小仙妹出马,肯定有所收获!

我刚才检查了一下 42F 的结果,都是正确的。


不知小仙妹用的什么算法?
能透露一下吗?

符合楼主要求的条件不?

[/Quote]

也是穷举。只不过穷举得比较快而已。


Function GetRlt2(ByVal pM As Byte, ByVal pK As Byte, ByVal pN As Byte) As Long
'返回能找到的第一个结果

Dim tOutValue As Long

Dim tCheckSum As Long

Dim tMixValue As Long

Dim tHBit As Long

tOutValues_Length = &HFF

ReDim tOutValues(tOutValues_Length)

For tHBit = 1 To &H7FFF

For tCheckSum = 0 To 255

tMixValue = tHBit * &H10000 + tCheckSum * &H100 + pM

If CheckSum(tMixValue) * pK + pN = tCheckSum Then

tOutValue = tMixValue

tCheckSum = 255: tHBit = &H7FFF

End If

Next

Next

GetRlt2 = tOutValue
End Function

Function GetRlt(ByVal pM As Byte, ByVal pK As Byte, ByVal pN As Byte) As Long()
'返回所有可能的结果。

Dim tOutValues() As Long
Dim tOutValues_Index As Long
Dim tOutValues_Length As Long

Dim tCheckSum As Long

Dim tMixValue As Long

Dim tHBit As Long

tOutValues_Length = &HFF

ReDim tOutValues(tOutValues_Length)

For tHBit = 1 To &H7FFF

For tCheckSum = 0 To 255

tMixValue = tHBit * &H10000 + tCheckSum * &H100 + pM

If CheckSum(tMixValue) * pK + pN = tCheckSum Then

If tOutValues_Index > tOutValues_Length Then

tOutValues_Length = tOutValues_Length + &HFF
ReDim Preserve tOutValues(tOutValues_Length)

End If

Debug.Print "&H" & Hex(tMixValue),
DoEvents

tOutValues(tOutValues_Index) = tMixValue
tOutValues_Index = tOutValues_Index + 1

End If

Next

Next

tOutValues_Length = tOutValues_Index - 1

ReDim Preserve tOutValues(tOutValues_Length)

GetRlt = tOutValues()
End Function

Function CheckSum(ByVal pValue As Long) As Long
'返回10进制校验和
Dim tOutCheckSum As Long
Dim tLoopValue As Long
Dim tLoopIndex As Long

tLoopValue = pValue

For tLoopIndex = 0 To 9

tOutCheckSum = tOutCheckSum + tLoopValue Mod 10
tLoopValue = tLoopValue \ 10

Next

CheckSum = tOutCheckSum
End Function
嗷嗷叫的老马 2010-01-10
  • 打赏
  • 举报
回复
算法白痴爬过~~~~~~~~~~~~~~~~~~~~
KiteGirl 2010-01-10
  • 打赏
  • 举报
回复
[Quote=引用 47 楼 chen8013 的回复:]
估计穷举法也基本上只能这样了。
不知道楼主的代码写成什么啥模样的。


小仙妹的‘10进制校验和’中 为什么要用 tLoopIndex = 0 To 9 啊,这样pValue无论是多少都是10次循环吧?

我倒是这样写的,小仙妹可否点评一下:
tOutCheckSum = 0
while (pValue > 0)
  tOutCheckSum = tOutCheckSum + pValue mod 10
  pValue = pValue \ 10
wend
我当时考虑这个问题时,这段代码没有写成函数,直接写在穷举循环中。
觉得就这么点儿代码,也只有那里用它,写成函数没必要。

[/Quote]

这个是习惯问题。当然这样写肯定很快。可以从1.9秒缩短到1.59秒
我是这样写的:
(while出现的时间比较早,后来的结构化BASIC推荐用Do Loop代替他。)


Function CheckSum(ByVal pValue As Long) As Long
Dim tOutCheckSum As Long
Dim tLoopValue As Long

tLoopValue = pValue

Do

tOutCheckSum = tOutCheckSum + tLoopValue Mod 10
tLoopValue = tLoopValue \ 10

Loop While tLoopValue

CheckSum = tOutCheckSum
End Function


对于这个算法可能还有个不穷举的办法,但需要研究。大概是这样的:

对10进制位中的9而言,加上以下的数字,则整体校验和改变量为:
加值 校验和改变
+1 -8
+2 -7
+3 -6
+4 -5
+5 -4
+6 -3
+7 -2
+8 -1
+9 -0

对于10进制位中的5而言
+1 +1
+2 +2
+3 +3
+4 +4
+5 -4
+6 -3
+7 -2
+8 -1
+9 -0

99+55,+5对应的校验和改变量是-4,那么加上55则校验和改变是-4*2=-8。
9+9=18
99+55=154
1+5+4=10(-8)

99+34,+3对应的校验和改变量是-6,+4对应的校验和改变量是-5。
那么加上34则校验和改变是-6+-5=-11。
9+9=18
99+34=133
1+3+3=7(-11)

根据这种规律,可以预先知道两个数相加后,校验和能改变多少。也有可能反推出需要加上一个什么数字能得到指定校验和。

SC×&H100+M最大也就是65536,只要能找到一个位数5位合适的HB,就能凑成一个SC和M特定情况下的合法的值。

由于是HB*&H10000+SC*&H100+M。
HB从0到&H7FFF,那么求出HB Mod 100000(10进制)的所有值,把它写到0-100000的数组里。
则可以建立一个表,这个表可以根据任意一个5位数去反求一个合适的HB。
计算这个表的过程是很快的,而且只算一次就可以。
在特定的SC和M情况下,不考虑HB先计算校验和。然后根据校验和去查表,选择一个合适的HB相加,凑成与SC对应的校验和。

这就是我考虑这个问题不用穷举法的大概思路。只是没时间去琢磨它。
KiteGirl 2010-01-09
  • 打赏
  • 举报
回复
以下是M=0 To 255,K=1,N=0情况下返回最先找到的第一个结果。

&H30E00 &H20D01 &H11202 &H31003 &H21504 &H11405 &H30F06 &H21107 &H11308 &H31409

&H20D0A &H1120B &H3100C &H2150D &H1140E &H30F0F &H21110 &H11311 &H31412 &H21613

&H11214 &H31015 &H21216 &H11717 &H30F18 &H21419 &H1131A &H30E1B &H2161C &H1121D

&H3101E &H2121F &H11720 &H30F21 &H21422 &H11323 &H30E24 &H21025 &H11226 &H31027

&H21228 &H11729 &H30F2A &H2142B &H1132C &H30E2D &H2102E &H1122F &H31030 &H21831

&H11432 &H31233 &H21434 &H11335 &H30E36 &H21037 &H11838 &H31039 &H20C3A &H1143B

&H30F3C &H2143D &H1133E &H30E3F &H21040 &H11241 &H31042 &H20C43 &H11444 &H30F45

&H21446 &H11347 &H30E48 &H21049 &H1124A &H3134B &H20C4C &H1144D &H30F4E &H2114F

&H11350 &H30E51 &H21052 &H11253 &H31354 &H21555 &H11456 &H30F57 &H21158 &H11659

&H30E5A &H2135B &H1125C &H30D5D &H20F5E &H1145F &H30F60 &H21161 &H11662 &H30E63

&H20D64 &H11265 &H30D66 &H20F67 &H11468 &H30F69 &H2116A &H1136B &H3116C &H2136D

&H1126E &H30D6F &H20F70 &H11771 &H30F72 &H20B73 &H11374 &H30E75 &H21376 &H11277

&H30D78 &H20F79 &H1177A &H30F7B &H20B7C &H1137D &H30E7E &H2137F &H11280 &H30D81

&H20F82 &H11183 &H30F84 &H20B85 &H11386 &H30E87 &H20788 &H11289 &H30D8A &H20F8B

&H1118C &H3128D &H20B8E &H1138F &H30E90 &H21091 &H11292 &H30D93 &H20F94 &H11195

&H31296 &H21497 &H11398 &H30E99 &H2109A &H1159B &H30D9C &H20C9D &H1119E &H30F9F

&H214A0 &H113A1 &H30EA2 &H210A3 &H112A4 &H313A5 &H20CA6 &H111A7 &H30FA8 &H214A9

&H113AA &H30EAB &H210AC &H112AD &H313AE &H215AF &H111B0 &H30FB1 &H211B2 &H116B3

&H30EB4 &H213B5 &H112B6 &H30DB7 &H215B8 &H111B9 &H30FBA &H211BB &H116BC &H30EBD

&H213BE &H112BF &H30DC0 &H20FC1 &H111C2 &H30FC3 &H211C4 &H116C5 &H30EC6 &H213C7

&H112C8 &H30DC9 &H20FCA &H111CB &H30FCC &H217CD &H113CE &H311CF &H213D0 &H112D1

&H30DD2 &H20FD3 &H117D4 &H30FD5 &H20BD6 &H113D7 &H30ED8 &H213D9 &H112DA &H30DDB

&H20FDC &H111DD &H30FDE &H20BDF &H113E0 &H30EE1 &H213E2 &H112E3 &H30DE4 &H20FE5

&H111E6 &H312E7 &H20BE8 &H113E9 &H30EEA &H210EB &H112EC &H30DED &H20FEE &H111EF

&H312F0 &H214F1 &H113F2 &H30EF3 &H210F4 &H115F5 &H30DF6 &H218F7 &H111F8 &H312F9

&H214FA &H113FB &H30EFC &H210FD &H115FE &H30DFF
KiteGirl 2010-01-09
  • 打赏
  • 举报
回复
fun(63, 1, 0)有32767种结果。
得到这些结果,在编辑状态运行程序用了20秒、在编译后运行用了1.9秒。
以下是其中的一部分。你看看是否都对。

&H1D282924 &H1D282F24 &H1D2B2E24 &H1D2E3024 &H1D2E3624 &H1D2E3924

&H1D312924 &H1D313224 &H1D313B24 &H1D343424 &H1D343D24 &H1D371E24

&H1D372124 &H1D372724 &H1D3A2924 &H1D3D2224 &H1D3D2824 &H1D3D2E24

&H1D402124 &H1D402424 &H1D402A24 &H1D403024 &H1D432924 &H1D432C24

&H1D461924 &H1D462224 &H1D462524 &H1D462B24 &H1D462E24 &H1D491B24

&H1D491E24 &H1D492424 &H1D492D24 &H1D4F2524 &H1D4F2B24 &H1D4F3124

&H1E512624 &H1E512924 &H1E512C24 &H1E512F24 &H1E542224 &H1E542824

&H1E542B24 &H1E571B24 &H1E572424 &H1E572D24 &H1E5A1A24 &H1E5A1D24

&H1E5A2324 &H1E5A2624 &H1E5A2F24 &H1E5D1F24 &H1E5D2224 &H1E5D2524

&H1E602124 &H1E602A24 &H1E602D24 &H1E631D24 &H1E632324 &H1E632624

&H1E632924 &H1E632C24 &H1E661324 &H1E661624 &H1E661C24 &H1E662224

&H1E690924 &H1E691224 &H1E691524 &H1E691824 &H1E691B24 &H1E691E24

&H1E6C1724 &H1E6C1D24 &H1E6C2024 &H1E721E24 &H1E722724 &H1E722A24

&H1E723024 &H1E752024 &H1E752924 &H1E752C24 &H1E753524 &H1E781C24

&H1E782224 &H1E7B1E24 &H1E7B2424 &H1E7B2724 &H1E7B2A24 &H1E7B2D24

&H1E7E2024 &H1E7E2624 &H1E7E2924 &H1E812B24 &H1E842724 &H1E843024

&H1E871A24 &H1E872024 &H1E872324 &H1E8A1F24 &H1E8D1B24 &H1E8D2124

&H1E8D2424 &H1E8D2724 &H1E8D2A24 &H1E901D24 &H1E902324 &H1E902624

&H1E902924 &H1E902C24 &H1E932224 &H1E932824 &H1E961824 &H1E962124

&H55B92C24 &H55BC1F24 &H55BC2824 &H55BC2B24 &H55BC2E24 &H55BC3124

&H55BC3424 &H55BF2A24 &H55BF2D24 &H55BF3324 &H55BF3624 &H55C22F24

&H55C23524 &H55C53124 &H55C53724 &H55C53A24 &H55C82724 &H55C82A24

&H55C83024 &H55CB2924 &H55CB2F24 &H55CE2824 &H55CE2B24 &H55CE3124

&H55CE3724 &H55D12724 &H55D12A24 &H55D12D24 &H55D13024 &H55D13324

&H55D42F24 &H55D43524 &H55D71924 &H55D71C24 &H55D71F24 &H55D72824

&H55DA2424 &H55DA2A24 &H55DD2024 &H55DD2324 &H55DD2624 &H55DD2924

&H55DD2F24 &H55E02224 &H55E02524 &H55E02B24 &H55E32D24 &H55E61A24

&H55E62324 &H55E91C24 &H55E92524 &H55EC2124 &H55EC2424 &H55EF2324

&H55EF2624 &H55EF2C24 &H55F21F24 &H55F22224 &H55F22524 &H55F22824

&H55F22E24 &H55F52124 &H55F52424 &H55F81724 &H55F82024 &H55F82324

&H55F82C24 &H55FB2224 &H55FE1E24 &H55FE2724 &H56012024 &H56012324

&H56012924 &H56013224 &H56041F24 &H56042824 &H56071E24 &H56072124
vbasic6 2010-01-08
  • 打赏
  • 举报
回复
手机看贴有点晕,还没完全没看明白要求。但感觉像是一个加密算法。先留个贴做个标记。回去再好好研究下。
vbman2003 2010-01-08
  • 打赏
  • 举报
回复
有意思的问题,建议直接转去算法版....
舉杯邀明月 2010-01-08
  • 打赏
  • 举报
回复
我也觉得可能是用于加密的。

Up 一下,静观其变…………
Fairphoenix 2010-01-07
  • 打赏
  • 举报
回复
谢谢 白云飞鹤师兄 的分析。
不过你这样不能解决实际问题啊,不能假设某个参数只能是多少。
理论上不能直接排除任何一个数(当然最高两字节和HHc为0的是可以排除的)。
在 M, K, N 的所有合法范围内,理论上可以覆盖全部的值域。

再等待一下吧,看有没有能够解决问题的高手出现。
我有点想在C++版去试试了…………
Fairphoenix 2010-01-07
  • 打赏
  • 举报
回复
Up一下……
今天有空来看看我的贴子。
可惜还是没有我所期望的答案,感觉有点失望啊,来问的问题都没有比较好的解决方案…………


[Quote=引用 33 楼 chinaboyzyq 的回复:]
引用 31 楼 chen8013 的回复:
看来只有‘穷举法’的解决方案 .............



不知道楼主想要什么?
本身[HHc]是不定的,[HHa][HHb]也是不确定的;不列举,如何直接得到结果?

[/Quote]
这位小哥的脾气还不小呢,先不说‘算法’如何,连答案都是错误的。

1。我的贴子说明了,我想找个“非穷举法”的算法。而你的还是穷举法。
2。你的算法是错误的。在你的 For i3 的循环中,把 N 加了多次。
3。你的代码运行效率太低了。这段代码中:
a = "&H" & Hex(i1) & Hex(i2) & Hex(m)
For i3 = 1 To Len(Format(a))
b = b + Mid(a, i3, 1) * k + N
Next

a,b 都是Long类型的,这段代码中存在多次的字符串类型与Long类型之间的自动转换。
说实在的,我根本不喜欢这样的代码。
nanbotaoci 2009-12-15
  • 打赏
  • 举报
回复
你们都太高深了
chinaboyzyq 2009-12-14
  • 打赏
  • 举报
回复

Function fun(m, k, N) As Long
Dim a As Long, b As Long, flg As Boolean
Dim i1 As Long, i2 As Integer, i3 As Integer

For i1 = 0 To Val(&H7FFF)
For i2 = 0 To Val(&HFF)
a = "&H" & Hex(i1) & Hex(i2) & Hex(m)
For i3 = 1 To Len(Format(a))
b = b + Mid(a, i3, 1) * k + N
Next
If b = i2 Then
fun = a
Exit Function
Else
b = 0
End If
Next
Next

End Function

mhm0517 2009-12-14
  • 打赏
  • 举报
回复


'我得出了以下结论:
'1. 当 N=0时.一定有解.
'所有的解为 [&H1 TO &H7FFF] * &HFFFF(65536)+ K * 256 + M
'2.因为你最大数为 &H7FFFFFFF(2147483647) 因此, 得到的数据每位数之和最大是(1999999999的和即82)
'因此以下面程序为例 i 的值最大不可能超过82
'又因为 i 的值是 每位数之和*N+K ;又因为每位数之和不可以是0 因此. i的值最小是 N+K
'且 每位数之和*N+K<256 于是有: (N +K)<= 每位数之和[ I 值] <= [(256-K)/N 与 82 之间的小者 ]

Private Function Fun(M, K, N) As Long
Dim i As Long
Dim j As Long
For i = 1 To &H7FFF '因为最高位是从 1 至 &H7FFF
For j = 0 To 90 '因为如果就算是 &H7FFF FFFF 最多10位十进制数.即 第二位 [HHc] 不可能超过90
'其实这里还可以加入条件. J 可以是 256/K(少于90)






If GetCount(i * 256 * 256 + j * 256 + M) * K + N = j Then '条件是否满足公式要求
Fun = i * 256 * 256 + j * 256 + M) * K + N
exit function '如果想得到所有,这里不要退出了.只得到一个要求,且有答案的,一秒内搞定
End If
Next
DoEvents
Next
End Function
chinaboyzyq 2009-12-14
  • 打赏
  • 举报
回复
[Quote=引用 31 楼 chen8013 的回复:]
看来只有‘穷举法’的解决方案 .............

[/Quote]

不知道楼主想要什么?
本身[HHc]是不定的,[HHa][HHb]也是不确定的;不列举,如何直接得到结果?
舉杯邀明月 2009-12-14
  • 打赏
  • 举报
回复
楼主可别“无满意答案结贴”啊,散分吧!

舉杯邀明月 2009-12-14
  • 打赏
  • 举报
回复
看来只有‘穷举法’的解决方案 .............

加载更多回复(29)

7,762

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧