dddddd
vb吧
全部回复
仅看楼主
level 7
skeiwi 楼主
@初音✨七奈 大佬怎么做才能不重复
2022年09月05日 08点09分 1
level 11
Option Explicit
Private Sub Command1_Click()
Dim a(0 To 100) As Integer
Dim i As Integer
Dim j As Integer
Dim t As Integer
Dim zuida As Integer
Dim weizhi As Integer
Randomize
For i = 0 To 100
a(i) = i
Next i
For i = 0 To 49
j = Int(Rnd * (101 - i)) + i
t = a(j)
a(j) = a(i)
a(i) = t
Print a(i);
If i Mod 10 = 9 Then Print
If a(i) >= zuida Then
zuida = a(i)
weizhi = i + 1
End If
Next i
Text1.Text = zuida
Text2.Text = weizhi
End Sub
2022年09月05日 11点09分 2
你这个洗牌是边洗边抽牌啊[滑稽]也挺好
2022年09月06日 11点09分
level 15
可以有好几种方法
常规方法:每生成一个新数字,都跟前面已经生成的数字进行比较,如果有相等的数字,则舍弃刚生成的新数字,重新再生成一个。这种方法需要使用三重循环,效率相对较低
Dim a(1 To 50) As Integer, i As Integer, j As Integer, k As Integer
k = 1
For i = 1 To 50
Do
a(i) = Int(Rnd * 101)
For j = 1 To i - 1
If a(j) = a(i) Then Exit For
Next j
Loop Until i = j
Print a(i);
If i Mod 10 = 0 Then Print
If a(i) > a(k) Then k = i
Next i
Text1.Text = a(k)
Text2.Text = k
随机乱序法(洗牌):将给定范围内的全部数字打乱顺序,再从打乱之后的序列中按顺序取出所需个数的数字。这种方法只需要使用三个并列的一重循环,效率较高
Dim a(100) As Integer, i As Integer, k As Integer, t As Integer
For i = 0 To 100
a(i) = i
Next i
For i = 0 To 100
k = Int(Rnd * 101)
t = a(i)
a(i) = a(k)
a(k) = t
Next i
k = 1
For i = 1 To 50
Print a(i);
If i Mod 10 = 0 Then Print
If a(i) > a(k) Then k = i
Next i
Text1.Text = a(k)
Text2.Text = k
反数组法(刚想的方法,随便起的名字[滑稽]):正常的数组,比如a(1)=5,表示的是第1个数的值为5;但如果反其道而行之,数组的下标表示数值,而数组元素的值表示数值的位置,仍然比如a(1)=5,表示的就变成了第5个数的值为1;然后仍然循环生成随机数,比如第1个数生成了10,就令a(10)=1,这样只要是生成过的数字,它对应的元素值就是它的位置,如果生成了已经存在的数字,则对应的元素值不为0,此时重新生成一个数即可。这种方法应该挺难理解的,而且效率也不是最高的(需要用二重循环),但我就是要把这种方法写出来[滑稽]
Dim a(100) As Integer, i As Integer, k As Integer
For i = 1 To 50
Do
k = Int(Rnd * 101)
Loop Until a(k) = 0
a(k) = i
Next i
For i = 100 To 0 Step -1
If a(i) <> 0 Then
Text1.Text = i
Text2.Text = a(i)
Exit For
End If
Next i
2022年09月05日 12点09分 3
最后一种方法漏掉了输出数字的代码,应该在a(k)=i的前面或者后面补上两行:Print k; : If i Mod 10 = 0 Then Print
2022年09月05日 12点09分
nb
2022年09月05日 12点09分
@初音✨七奈 我想问下 If i Mod 10 = 0 Then Print这句意思是啥
2022年09月05日 13点09分
@skeiwi 就是每满10个数换行
2022年09月05日 13点09分
level 9
3楼的第三个方法其实可以更简单,使用位图(BitMap)
每生成一个随机数之后,判断这个随机数对应的位是否为1,如果是0,计数器加1,并把该位设为1
只需要一个循环
2022年09月06日 00点09分 5
level 9
也可以用哈希表
哈希表模块在这个贴子里 https://tieba.baidu.com/p/4130111113
示例代码:
Dim ht As New HashTable
Dim k, iKey As Integer, i As Long, Result As String
Cls
Randomize
Do
iKey = Int(Rnd * 101)
If ht.Exists(CStr(iKey)) = False Then ht.Add CStr(iKey), 1
Loop Until ht.Count = 50
For Each k In ht.Keys
i = i + 1
Result = Result & k & vbTab
If i Mod 10 = 0 Then Result = Result & vbNewLine
Next
Print Result
2022年09月06日 01点09分 6
level 9
位图算法的代码:
Dim BitMap As String, i As Integer, j As Integer, RN As Integer, Result As String
BitMap = Space(101)
Randomize
Do
RN = Int(Rnd * 101)
If Mid(BitMap, RN + 1, 1) <> 1 Then
Mid(BitMap, RN + 1, 1) = 1
i = i + 1
End If
Loop Until i = 50
For i = 1 To Len(BitMap)
If Mid(BitMap, i + 1, 1) = 1 Then
Result = Result & i & vbTab
j = j + 1
If j Mod 10 = 0 Then
Result = Result & vbNewLine
End If
End If
Next
Cls
Print Result
2022年09月06日 01点09分 7
位图本来应该用字节数组实现,速度更快,占用空间更小。但是只要不是太大量的数据,用字符串实现位图也能满足需求
2022年09月06日 01点09分
[熊-谢谢你]
2022年09月11日 02点09分
level 9
Option Explicit
Private Sub Command1_Click()
Dim a(0 To 49) As Integer
Dim i As Integer
Dim iMax As Integer
Dim iPos As Integer
Randomize
For i = 0 To 49
a(i) = Int(Rnd * (100 + 1))
Print a(i) & " ";
If i Mod 10 = 9 Then Print
If a(i) > iMax Then
iMax = a(i)
iPos = i
End If
Next i
Text1.Text = iMax
Text2.Text = iPos + 1
End Sub
2022年09月21日 06点09分 8
关键是要数字不重复,你这样没有对重复数字进行排除
2022年09月21日 10点09分
@初音✨七奈 没仔细审题啊[汗] 要是不重复, DiverAZAM和你的方法二还是比较直观的
2022年09月27日 09点09分
level 12
用list控件,顺序生成1-100的数字。
然后产生随机0到list控件最大列表的随机数,取其中list(x)的值,取50次即可。
2022年09月24日 16点09分 10
level 1
这个问题也可以用List控件实现。
先做一个小学数学问题。0-100中,随机抽50个数,每个数被选中的概率为50/101。这里50为“还需要抽取的数量”,101为“尚未被抽取的数量”
那么,可以很容易反过来得到0-100依次循环,每一个数被选中的概率=“还需要抽取的数量”/“尚未被抽取的数量”。
List控件的作用主要为打乱,也就是洗牌:List1.AddItem <内容>, Int(Rnd * (List1.ListCount + 1))。随机将内容插入至List1中。其中,"当前已经抽取的数量"就是List1.ListCoun,那么“还需要抽取的数量”=“抽取总数”-List1.ListCoun。
在For i = Min(范围最小值) to Max(范围最大值)中,“尚未被抽取的数量” = Max - i + 1
由此得代码:
List1.Clear
For i = TheMin To TheMax
Randomize
If Rnd() < (TheCount - List1.ListCount) / (TheMax - i + 1) Then
List1.AddItem i, Int(Rnd * (List1.ListCount + 1))
End If
Next
2023年02月15日 07点02分 12
[滑稽]简单粗暴,单次循环,单次判断,取两次随机数,全加减乘除。缺点是只能随机整数。而且当范围远大于需要抽取个数时,时间会相应较长。但当需要抽取的数量接近范围中元素数量时,效率极高。
2023年02月15日 07点02分
在实际应用时,如果不要求抽取的数被打乱时,还能更快。比如扫雷,这个代码可以轻松解决整个扫雷只有一个空格时,随机地雷问题
2023年02月15日 07点02分
如果只是随机抽取X个,不要求抽取的数被打乱,List1.AddItem i, Int(Rnd * (List1.ListCount + 1))这一行直接换成输出就行
2023年02月15日 07点02分
其中,概率判断这一行Rnd() < (TheCount - List1.ListCount) / (TheMax - i + 1)一定是小于号,只有小于号能做到概率为0%时,[0,1)的随机数一定不满足,同时概率为100%时,[0,1)的随机数一定满足。虽然[0,1)的随机数你不可能取到0[呵呵]
2023年02月15日 07点02分
level 1
@你看上去很欧
假设TheMax = 10,TheMin = 1,TheCount = 3
第一个数字被抽中的概率为3/10
第二个数字被抽中的概率为3/10*2/9+7/10*3/9= 3/10
其中,2/9和3/9为公式(TheCount - List1.ListCount) / (TheMax - i + 1)在每一种情况下求得的概率,证得第二个数由公式求得的概率与预期3/10一致,公式正确
第三个数字被抽中的概率为3/10*2/9*1/8
+3
/10*7/9*2/8+7/10*3/9*2/8+7/10*6/9*3/8=3/10
其中,1/8、2/8、2/8和3/8为公式(TheCount - List1.ListCount) / (TheMax - i + 1)在每一种情况下求得的概率,证得第三个数由公式求得的概率与预期3/10一致,公式正确
。。。。。。以此类推
这个公式是没问题的,至于楼主的其他问题,我稍微加两行代码来满足就行了:
Dim TheMax As Integer
Dim TheMin As Integer
Dim TheCount As Integer
TheMax = 100
TheMin = 0
TheCount = 50
Cls
List1.Clear
Randomize
Dim TheRnd As Double
For i = TheMin To TheMax
If Rnd() < (TheCount - List1.ListCount) / (TheMax - i + 1) Then
If TheCount = List1.ListCount + 1 Then
Text1.Text = i: Text2.Text = Int(Rnd * (List1.ListCount + 1) + 1)
List1.AddItem i, (Val(Text2.Text) - 1)
Else
List1.AddItem i, Int(Rnd * (List1.ListCount + 1))
End If
End If
Next
For i = 0 To TheCount
Print List1.List(i) & " ";
If i Mod 10 = 9 Then Print
Next
我实际测试的运算速度,在不考虑输出与输出顺序的情况下,也就是直接把值传递给下一过程,仅作为中间过程使用。抽了2楼的洗牌、7楼位图和我的概率
2楼的洗牌+抽牌运算速度在各种参数下速度最快
7楼在抽取数量较少时运算速度较快,但还是没2楼快
我的概率算法和7楼相反,但远大于2楼的用时
测试结果是2楼的抽牌速度在各种参数下最强(别杠抽一两张牌的时候)
2023年02月15日 09点02分 13
我的扫雷的格子序号不是按顺序写的,格子的序号中千位和百位负责表示横坐标十位和个位表示纵坐标。而且并没有变量负责记录这些格子的序号,所以抽取的时候概率最强。综上,概率法只能当一种特解,大家看个乐呵就好了[太开心]
2023年02月15日 09点02分
@- 你之前说的,分母在变,但你也应该发现list1.count也在变,每抽一次都加了一项[吐舌]。这个特化方法是针对for each...in...的,所以只要抽几张,不需要保证抽的顺序,list只是简单打乱,还是太慢了。
2023年02月15日 11点02分
@- 实际操作时可以设两个变量,一个每次被抽到就减一,一个每循环一次减一,来代替分子分母
2023年02月15日 11点02分
我有看了下7楼的位图算法,其实本质上和二楼的方法三是一样的,之所以只有一个循环,速度还不如洗牌,是因为越往后,猜中的概率越低。
2023年03月06日 00点03分
1