高分挑战算法高手

mmxer 2000-11-13 12:44:00
设从m个数中取出n个数组成一组数(m>=n),共能组合成x组数,求算法能组合出这x组数,并显示出来。
...全文
437 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
BCB 2000-11-18
  • 打赏
  • 举报
回复
请把程序略加改动,假设 m=4,n=6,定义
char * d[]={"","A","B","C","D","1","2"};
// 这是C++ 的串数组,第一空串不用,C++数组下标总是从0开始,
再运行一遍,不就得到这些串的排列:
a b c d
a b c 1
a b c 2
....
....
c d 1 2


BCB 2000-11-18
  • 打赏
  • 举报
回复
n,m为整数对吧,
你可能未了解我的这段程序的意思,
我的D[]数组可以为任意类型,例如串,甚至变体,
通过对自然数1..m排列数作为下标再去访问原数组D[]
不就得D数组的每一组排列,
我之所以取D数组也是自然数,是可考虑到:太复杂会造成
C++BUILDER与DELPHI 转换可能困难。
请你把你的原意要求举个例子,我再看看,相信我定能解决
你的问题,只要你看C++bilder不困难.
(上面的程序花了晚上三小时)









mmxer 2000-11-18
  • 打赏
  • 举报
回复
谢谢BCB前辈指点,您的方法是能解决一定的问题,但我所指的n个数并非指1..n之间的自然数,m也非1..m之间的自然数,而是任意数组合,但m必须是n的子集。
BCB 2000-11-18
  • 打赏
  • 举报
回复
bool GetNext(int x[],int m,int n)
{ // 求排列的下一组,若有返true,否则为假
for (int i=m;i>=1;i--)
{
int b=x[i];
if (b<n-m+i) //x[i]是否到了极限n-m+i
{
for (int j=i;j<=m;j++)
{
b=b+1;
x[j]=b;
}
return(true);
}
}
return(false); // 元素全到了极限,该结束了
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
#define MaxN 100
char *d[MaxN]; // 存放待排列的N个串
int x[MaxN]; // 存放M个排列下标数
int m=4,n=6; // 从N数中取M个排列数
int js=0; // 组计数

d[1]="甲"; d[2]="乙";
d[3]="丙"; d[4]="丁";
d[5]="戊"; d[6]="已";

for (int i=1;i<=m;i++)
x[i]=i; // 排列的首组下标,M个数
do
{
String s="";
for (int i=1;i<=m;i++)
s=s+String(d[x[i]])+" ";
Memo1->Lines->Add(s); // 显示
js=js+1;
}
while (GetNext(x,m,n)); //找下一组排列
Memo1->Lines->Add("共 "+String(js)+" 组");
}

甲 乙 丙 丁
甲 乙 丙 戊
甲 乙 丙 已
甲 乙 丁 戊
甲 乙 丁 已
甲 乙 戊 已
甲 丙 丁 戊
甲 丙 丁 已
甲 丙 戊 已
甲 丁 戊 已
乙 丙 丁 戊
乙 丙 丁 已
乙 丙 戊 已
乙 丁 戊 已
丙 丁 戊 已
共 15 组



hu_zy 2000-11-18
  • 打赏
  • 举报
回复
我简单说一下,只需要限定后面的数组的下标下限大于前一个素的当前值就可以了。
for (i[1]=0;i[1]<n;i[1]++)
for (i[2]=i[1];i[2]<n;i[2]++)
...........
for(i[m]=i[m-1];i[m]<n;i[m]++)
for (j=0;j<m;j++)
print trap[i[j]];
就可以了。
BCB 2000-11-16
  • 打赏
  • 举报
回复
boolean Function GetNext(x: Array[1..MaxN] of integer;
m:integer;n:integer)
应为:
Function GetNext(x: Array[1..MaxN] of integer;
m:integer;n:integer):boolean
本人Pascal已有十年未用了, 到了Delphi变化更大了。

若改成Delphi有问题, 请再留言!






BCB 2000-11-15
  • 打赏
  • 举报
回复
// 下面m,n跟标题的n,m弄反了,见谅,下面 m<=n
这个排列问题很有趣,我尝试了一下,能达到目的,可是我只习
惯用C++Builder,为了便于改成DELPHI,尽量采用相近的语句;
待排列的N个不同的元素,每次只取M个,M<=N,共有C(M,N)组,
如C(3,5)=5*4*3/(1*2*3)=10组,
假设把n个数或串 保存到数组d[1].....d[n]中,
其实我们可简化成:只要对自然数1..N每次取M个一组进行排
列,这个M个保存在数组 x[1]...x[m]中,通过x[i]作为下标再去访
问原数组d[ ]就可,即d[x[i]];
首先,对于自然数,我们要掌握如何用手工列出这C(3,5)组:
1 2 3 // 首组
1 2 4 // x[3]+1->x[3]
1 2 5 // x[3]+1->x[3]
1 3 4 // x[4]已达极限值5,x[2]+1->x[2],x[2]+1->x[3]
1 3 5 // x[3]+1->x[3]
1 4 5 // x[3]已达极值5,x[2]+1->x[2],x[2]+1->x[3]
2 3 4 // x[2] x[3]达极值4和5,x[1]+1->x[1],....
2 3 5 // x[3]+1->x[3]
2 4 5 // x[2]+1->x[2]
3 4 5 // x[1] x[2] x[3]分别已达极限值 3 4 5,结束!
实际从第一组 1 2 3 每次求它的相邻下一组,从右向左看每一个
x[i],若第一个x[i]未到达它的极限值n-m+i,就把x[i]+1->x[i],
立即退出,若x[i]已达极值,继续向左查找未达极值的x[i],
找到后x[i]+1->x[i],后面的单元依次填入x[i]+1,......;
若全部达极限值,说明已穷举完毕;
下面的GetNext(int x[ ],int m,int n)就是找下一组,若成功
返回true,且x[ ]中的M个数x[1]....x[m]就是排列数;

bool GetNext(int x[],int m,int n)
{ // 求排列的下一组,若成功返true,否则为假
for (int i=m;i>=1;i--)
{
int b=x[i];
if (b<n-m+i) //x[i]是否到了极限n-m+i
{
for (int j=i;j<=m;j++)
{
b=b+1; x[j]=b;
}
return(true);
}
}
return(false); // 全到了极限值,该结束了
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
#define MaxN 100
int d[MaxN]; // 存放待排列的N个数
int x[MaxN]; // 存放M个排列下标数
int m=4,n=6; // 从N数中取M个排列数
int js=0; // 组计数
for (int i=1;i<=n;i++)
d[i]=i; // 待排列的N个数,这里也放自然数

for (int i=1;i<=m;i++)
x[i]=i; // 排列的首组下标,M个数
do
{
String s="";
for (int i=1;i<=m;i++)
s=s+String(d[x[i]])+" ";
Memo1->Lines->Add(s); // 显示每一组
js=js+1;
}
while (GetNext(x,m,n)); //找下一组排列
Memo1->Lines->Add("共 "+String(js)+" 组");
}

Memo1控件用作显示每一组数,上例中待排列的单元d[1]....d[n]
放的也是自然数,其实可以为任意类型的数组,所以本程序有一定的
通用性;对于GetNext( )下面尝试改作Pascal或Delphi,语法很相似,
可能不太行,仅供参考:

boolean Function GetNext(x: Array[1..MaxN] of integer;
m:integer;n:integer)
var i,j,b:integer;
begin { 求排列的下一组,若有返true,否则为假 }
for i:=m downto 1
begin
b:=x[i];
if (b<n-m+i) then {x[i]是否到了极限n-m+i}
begin
for j:=i to m
begin
b:=b+1; x[j]:=b;
end
GetNext:=true;
return; { 退出函数 }
end
end
GetNext:=false;
return; { 全到了极限,该结束了 }
end


另外C++的循环do while(条件)等同Psacal的Repeat until not 条件,
但条件要取not.







bridge 2000-11-15
  • 打赏
  • 举报
回复
我记得清华一个教授出了本《组合数学》好象是这个名字,其中将排列,组合将的很详细,
求组合的算法就有很详细的说法,而且有理论证明。
bitter 2000-11-15
  • 打赏
  • 举报
回复
哈哈!
这是组合。从m个数a[m](设为一个数组)中选出n个。方法如下:
1、选a[0]做第一位,第二位有n-1可能,第三位有n-2种可能。。。。
2、选a[1]做第一位,第二位有n-2中可能(因为a[0]不能再用)第三位有n-3中可能。。。
。。。

总的可能数 m*(m-1)*(m-2)....*n/n*(n-1)*(n-2)*.....*1
关键是如何选数,才能不重复。

大概是这样的
mmxer 2000-11-15
  • 打赏
  • 举报
回复
谢谢wzs,我想问的就是你说的那一种,23465和65432是同一组数字,不能出现两次,有什么方法能不能帮帮我?
wzs 2000-11-14
  • 打赏
  • 举报
回复
这个我曾有做过类似的问题,不过你没讲清楚就是组成的那些组数有没有重复?我指如下:
1组:23465 但以后不能再出现1组中所列的数,不管轶次序是否相同如65342说透了就是体育彩票的筛选条件如果是的话很难做到所有的排列组合出来如果不是那就好办了,求出来的组数我想应等于
1*2*3*....m个数据(阶乘).
mmxer 2000-11-14
  • 打赏
  • 举报
回复
我是乡野粗人,麻烦指点一下。
cwhelucky 2000-11-13
  • 打赏
  • 举报
回复
这不是算法呀,试试排列组合好不好
51go 2000-11-13
  • 打赏
  • 举报
回复
are u joking?it is not so difficult..a lot of math books has the answer..
gameboy999 2000-11-13
  • 打赏
  • 举报
回复
你是寻开心还是真需要???高程的书里有类似的算法.

5,392

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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