多个数组组合算法

fastgun 2009-01-12 04:07:02
m个数组,每个数组取1个数字,进行组合(不排序)得到各种组合的算法
...全文
112 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
fastgun 2009-01-13
  • 打赏
  • 举报
回复
谢谢!
我自己解决了!
wxrwan 2009-01-12
  • 打赏
  • 举报
回复
一个排列组合的类模块。
Option Explicit

' 所谓回溯:就是搜索一棵状态树的过程,这个过程类似于图的深度优先
' 搜索(DFS),在搜索的每一步(这里的每一步对应搜索树的第i层)中
'产生一个正确的解,然后在以后的每一步搜索过程中,都检查其前一步
'的记录,并且它将有条件的选择以后的每一个搜索状态(即第i+1层的 状态节点)。

' 需掌握的基本算法:
'排列:就是从n个元素中同时取r个元素的排列,记做P(n,m)。(当m=n时,
'我们称P(n,n)=n!为全排列) 例如我们有集合OR = {1,2,3,4},那么
' n = |OR| = 4, 且规定r=3, 那么P(4,3)就是:
'{1,2,3}; {1,2,4}; {1,3,2}; {1,3,4}; {1,4,2}; {1,4,3};
' {2,1,3}; {2,1,4}; {2,3,1}; {2,3,4}; {2,4,1}; {2,4,3};
' {3,1,2}; {3,1,4}; {3,2,1}; {3,2,4}; {3,4,1}; {3,4,2};
'{4,1,2}; {4,1,3}; {4,2,1}; {4,2,3}; {4,3,1}; {4,3,2}

Private n As Integer, m As Integer
Private pNum As Integer
Private used() As Integer
Private p() As String
Private Data As Variant
Private PData As Variant

'排列组合
Public Sub Permute(vData As Variant, iPm As Integer, vPData As Variant)

Data = vData
n = UBound(vData) - LBound(vData) + 1
If iPm <= n Then
m = iPm
Else
m = n
End If

ReDim used(n - 1)
ReDim p(m - 1)

pNum = 0
ReDim PData(Pnm(n, m) - 1, m - 1)

Permute0 0

vPData = PData

End Sub

'组合
Public Sub Combine(vData As Variant, iPm As Integer, vPData As Variant)

Data = vData
n = UBound(vData) - LBound(vData) + 1

If iPm <= n Then
m = iPm
Else
m = n
End If

ReDim used(n - 1)
ReDim p(m - 1)

pNum = 0
ReDim PData(Cnm(n, m) - 1, m - 1)
Combine0 0, 0
vPData = PData

End Sub


' permute(pos -- 表示在解空间中填写数据的下标位置)
'{ 如果解空间填写满了 打印解空间当前的排列结果 函数返回
' for (i=0; i<n; i++) -- n是待排列数据总数
' {
' 尝试在这个下标位置填写每一个待排列的数据
' (但这些数据可填写的前提是数据没有被标记为已使用)
'
' 填写后, 把这个下标为i的数据标记为已使用 '
' permute(pos+1); -- 填写解空间中下一个位置 '
' 下标为i的数据已参与了解空间下标pos处的排列 '
'取消已使用标记(因为该数据可以在解空间其他下标处使用)
' 继续for循环考察下一个待排列数据
' }
' }
'
' used[i] == 1 - 待排列空间中下标i处的数据已被使用;
' used[i] == 0 - 可以使用待排列空间中下标i处的数据;

Private Sub Permute0(pos As Integer)
Dim i As Integer
If pos = m Then
For i = 0 To m - 1
PData(pNum, i) = p(i)
Next
pNum = pNum + 1
Exit Sub
End If
For i = 0 To n - 1
If used(i) = 0 Then
used(i) = used(i) + 1
p(pos) = Data(i)
Permute0 (pos + 1)
used(i) = used(i) - 1
End If
Next i

End Sub

'组合
'idx--记录下标pos处的i的位置
Private Sub Combine0(pos As Integer, idx As Integer)
Dim i As Integer
If pos = m Then
For i = 0 To m - 1
PData(pNum, i) = p(i)
Next
pNum = pNum + 1
Exit Sub
End If
For i = idx To n - 1
If used(i) = 0 Then
used(i) = used(i) + 1
p(pos) = Data(i)
Combine0 (pos + 1), i
used(i) = used(i) - 1
End If
Next i

End Sub

'计算排列组合的个数
'n*(n-1)*(n-2)*...*(n-m+1) m个
Public Function Pnm(n As Integer, m As Integer) As Long
If m > n Then
m = n
End If
If m = 0 Then
Pnm = 1
Exit Function
Else
Pnm = n * Pnm(n - 1, m - 1)
End If

End Function

'计算组合的个数
Public Function Cnm(n As Integer, m As Integer) As Long
If m > n Then
m = n
End If
Cnm = Pnm(n, m) / Pnm(m, m)

End Function
fastgun 2009-01-12
  • 打赏
  • 举报
回复
上面的代码已经明白了,不知有无更好的算法?
fastgun 2009-01-12
  • 打赏
  • 举报
回复
看到一段C语言的代码,不太懂,帮我转为VB的代码,或者解释一下思路,也希望有好的解决方法,谢谢!

#include <iostream.h>

int *a[3];
int b1[5]={4,1,2,3,4};
int b2[4]={3,5,6,7};
int b3[3]={2,8,9};
int c[3]={0};

void order(int n)
{
int i;
if(n>=3)
{
for( i=0 ; i<3 ; ++i )
cout<<c[i]<<" ";
cout<<endl;
return ;
}
for( i=1 ; i<=a[n][0] ; ++i )
{
c[n]=a[n][i];
order(n+1);
}
}

int main()
{
a[0]=b1;
a[1]=b2;
a[2]=b3;
order(0);
return 0;
}
这里n=3,可以根据你的要求把程序改改

7,765

社区成员

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

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