- 相關(guān)推薦
一個(gè)組合數(shù)的求解方法
有從10個(gè)不同的數(shù)中取出7個(gè),如何求出所有組合?
初看這個(gè)問(wèn)題,確實(shí)不太好下手,雖然我們理解這個(gè)問(wèn)題很容易,但要讓計(jì)算機(jī)“理解”可得花點(diǎn)功夫了。
先分析:首先想到,如果由10個(gè)元素中的7個(gè)組成一個(gè)序列,并且這7個(gè)元素互不相等,這就比較接近于正解了;然后考慮,組合中7元素是不分先后的,我們?nèi)绾翁蕹嘤嗟臄?shù)據(jù)呢(如四選二中(1,3)與(3,1)是相同解)?
我們可以在編程時(shí)作一種限定,7個(gè)元素的排列順序滿足我們的一個(gè)規(guī)定,這樣,就可以依據(jù)相同位置的值不能相同來(lái)排除不正確的解。
這樣我們的第一個(gè)解呼之欲出了:可以利用數(shù)組來(lái)進(jìn)行選取,不同的數(shù)組下標(biāo)順序就代表了不同的解,而且我們約定這個(gè)下標(biāo)序列必須是升序,這就利于我們排除冗余值。
在本文中,約定這10個(gè)數(shù)是如下形式的數(shù)組,并且已經(jīng)賦值。計(jì)算的結(jié)果在一個(gè)TMemo控件中顯示。
var
Value:array[1..10] of integer;
解法一、
按鈕1的點(diǎn)擊事件處理。
procedure TForm1.Button1Click(Sender: TObject);
var
idx1,idx2,idx3,idx4,idx5,idx6,idx7: integer;
tmpStr:string;
begin
Memo1.Lines.Clear;
for idx1:=1 to 4 do
for idx2:=idx1+1 to 5 do
for idx3:=idx2+1 to 6 do
for idx4:=idx3+1 to 7 do
for idx5:=idx4+1 to 8 do
for idx6:=idx5+1 to 9 do
for idx7:=idx6+1 to 10 do
begin
tmpStr:=IntToStr(idx1)+' '+IntToStr(idx2)+' '+IntToStr(idx3)
+' '+IntToStr(idx4)+' '+IntToStr(idx5)+' '+IntToStr(idx6)
+' '+IntToStr(idx7) ;
Memo1.Lines.Add(tmpStr);
end;
end;
解中只顯示了下標(biāo)的組合,實(shí)際應(yīng)用把下標(biāo)改為Value數(shù)組即可:tmpStr:=IntToStr(Value[idx1])+' '+IntToStr(Value[idx2])+...; 。
這個(gè)解的一個(gè)亮點(diǎn)就是每一個(gè)循環(huán)變量的初值都是它前一個(gè)變量加1;這就保證后一個(gè)下標(biāo)一定不等于前一個(gè)下標(biāo),請(qǐng)?bào)w會(huì)一下為什么循環(huán)控制變量的終值為4~10。
解法二、
中學(xué)的數(shù)學(xué)教材中就講到C(10,7)=C(10,3),這個(gè)很好理解,從10中選7,剩下3個(gè),所有選七的組合完成,也就是所有選三的組合完成,反之亦然。
按鈕2的點(diǎn)擊事件處理:
procedure TForm1.Button2Click(Sender: TObject);
var
idx1,idx2,idx3,idx4: integer;
tmpStr:string;
begin
Memo1.Lines.Clear;
for idx1:=1 to 8 do
for idx2:=idx1+1 to 9 do
for idx3:=idx2+1 to 10 do
begin
tmpStr:='';
for idx4:=1 to 10 do
if (idx4<>idx1) and (idx4<>idx2) and (idx4<>idx3) // 加入一個(gè)元素
then tmpStr:=tmpStr+IntToStr(Value[idx4])+' ';
Memo1.Lines.Add(tmpStr);
end;
end;
這個(gè)解是十選三,然后顯示剩下的七個(gè),是不是有點(diǎn)意思呢?
以上加入元素的判斷可以改寫為:
if ((idx1+100)*(idx2+100)*(idx3+100) mod (idx4+100) >0 )
請(qǐng)?bào)w會(huì)一下同余理論的運(yùn)用,這里利用了101到110這十個(gè)數(shù)中任一個(gè)數(shù)都不被其它三個(gè)數(shù)的乘積整除的特性
解法三、
以上兩解也可用集合來(lái)實(shí)現(xiàn)。
再想想,以上兩解都是用了多重循環(huán),必須定義多個(gè)循環(huán)變量,通用性似乎差了點(diǎn)。
觀察這些循環(huán)(尤其是解一),形式是何等的一致!
也許諸位已經(jīng)想到我要用遞歸調(diào)用來(lái)解決這個(gè)問(wèn)題了。
要設(shè)計(jì)遞歸,首先要確定哪些變量是必須向這個(gè)函數(shù)傳遞的,容易知道,調(diào)用時(shí)要知道當(dāng)前元素的起始下標(biāo)與終止下標(biāo),當(dāng)然還有兩個(gè)必不可少的參數(shù)就是我這個(gè)函數(shù)計(jì)算的是從多少選多少的,這樣就確定了四個(gè)參數(shù)。
還有一個(gè)要注意的地方,是遞歸何時(shí)顯示數(shù)據(jù)?顯然應(yīng)當(dāng)在求最后一個(gè)元素時(shí)。
(關(guān)于遞歸調(diào)用的一些詳細(xì)的論述,可以參看喬林的《參透Delphi/Kylix》一書或其它教材)
請(qǐng)看實(shí)現(xiàn):
全局變量
var
GIDX:array[1..20] of integer; // 記錄下標(biāo)的數(shù)組。
procedure MyRecur(Total,SelCnt,BLoc,ELoc:integer);
var
idx,jjj:integer;
tmpStr:string;
begin
if (ELoc=Total) // 終止?fàn)顟B(tài)
then begin
for idx:=BLoc to ELoc do
begin
GIDX[SelCnt+ELoc-Total]:=idx; // 注意此處應(yīng)與下面 8888處一致
tmpStr:='';
for jjj:=1 to SelCnt do tmpStr:=tmpStr+IntToStr(Value[GIDX[jjj]])+' ';
Form1.Memo1.Lines.Add(tmpStr);
end;
end
else begin
for idx:=BLoc to ELoc do
begin
GIDX[SelCnt+ELoc-Total]:=idx; // 8888
MyRecur(Total,SelCnt,idx+1,ELoc+1);
end;
end;
end;
procedure SelNumber(Total,SelCnt:integer);
begin
if (Total<1) or (Total<SELCNT)< p>
then begin
ShowMessage('數(shù)據(jù)不正確!');
Exit;
end;
MyRecur(Total,SelCnt,1,Total-SelCnt+1); // 最初第三個(gè)參數(shù)總為1
end;
使用:
procedure TForm1.Button3Click(Sender: TObject);
var
ttl,sel:integer;
begin
Memo1.Clear;
ttl:=StrToInt(Edit1.Text); // 請(qǐng)自己加上對(duì)TEdit的容錯(cuò)處理。
sel:=StrToInt(Edit2.Text);
SelNumber(ttl,sel);
end;
好了,在Edit1中輸入‘100’,在Edit2中輸入'3',執(zhí)行試試,三十多萬(wàn)行的數(shù)據(jù)不斷地滾出來(lái)了吧。
建議在計(jì)算前先估算一下共多少組合,最好不要超過(guò)10萬(wàn)。
相關(guān)推薦:
經(jīng)濟(jì)師資格證
2013年經(jīng)濟(jì)師考試時(shí)間
可不參加職稱外語(yǔ)考試的條件
廣州2013年職稱英語(yǔ)考試報(bào)名
大專生怎獲取學(xué)位、報(bào)考研究生
跨國(guó)公司需要考取那些證書
初看這個(gè)問(wèn)題,確實(shí)不太好下手,雖然我們理解這個(gè)問(wèn)題很容易,但要讓計(jì)算機(jī)“理解”可得花點(diǎn)功夫了。
先分析:首先想到,如果由10個(gè)元素中的7個(gè)組成一個(gè)序列,并且這7個(gè)元素互不相等,這就比較接近于正解了;然后考慮,組合中7元素是不分先后的,我們?nèi)绾翁蕹嘤嗟臄?shù)據(jù)呢(如四選二中(1,3)與(3,1)是相同解)?
我們可以在編程時(shí)作一種限定,7個(gè)元素的排列順序滿足我們的一個(gè)規(guī)定,這樣,就可以依據(jù)相同位置的值不能相同來(lái)排除不正確的解。
這樣我們的第一個(gè)解呼之欲出了:可以利用數(shù)組來(lái)進(jìn)行選取,不同的數(shù)組下標(biāo)順序就代表了不同的解,而且我們約定這個(gè)下標(biāo)序列必須是升序,這就利于我們排除冗余值。
在本文中,約定這10個(gè)數(shù)是如下形式的數(shù)組,并且已經(jīng)賦值。計(jì)算的結(jié)果在一個(gè)TMemo控件中顯示。
var
Value:array[1..10] of integer;
解法一、
按鈕1的點(diǎn)擊事件處理。
procedure TForm1.Button1Click(Sender: TObject);
var
idx1,idx2,idx3,idx4,idx5,idx6,idx7: integer;
tmpStr:string;
begin
Memo1.Lines.Clear;
for idx1:=1 to 4 do
for idx2:=idx1+1 to 5 do
for idx3:=idx2+1 to 6 do
for idx4:=idx3+1 to 7 do
for idx5:=idx4+1 to 8 do
for idx6:=idx5+1 to 9 do
for idx7:=idx6+1 to 10 do
begin
tmpStr:=IntToStr(idx1)+' '+IntToStr(idx2)+' '+IntToStr(idx3)
+' '+IntToStr(idx4)+' '+IntToStr(idx5)+' '+IntToStr(idx6)
+' '+IntToStr(idx7) ;
Memo1.Lines.Add(tmpStr);
end;
end;
解中只顯示了下標(biāo)的組合,實(shí)際應(yīng)用把下標(biāo)改為Value數(shù)組即可:tmpStr:=IntToStr(Value[idx1])+' '+IntToStr(Value[idx2])+...; 。
這個(gè)解的一個(gè)亮點(diǎn)就是每一個(gè)循環(huán)變量的初值都是它前一個(gè)變量加1;這就保證后一個(gè)下標(biāo)一定不等于前一個(gè)下標(biāo),請(qǐng)?bào)w會(huì)一下為什么循環(huán)控制變量的終值為4~10。
解法二、
中學(xué)的數(shù)學(xué)教材中就講到C(10,7)=C(10,3),這個(gè)很好理解,從10中選7,剩下3個(gè),所有選七的組合完成,也就是所有選三的組合完成,反之亦然。
按鈕2的點(diǎn)擊事件處理:
procedure TForm1.Button2Click(Sender: TObject);
var
idx1,idx2,idx3,idx4: integer;
tmpStr:string;
begin
Memo1.Lines.Clear;
for idx1:=1 to 8 do
for idx2:=idx1+1 to 9 do
for idx3:=idx2+1 to 10 do
begin
tmpStr:='';
for idx4:=1 to 10 do
if (idx4<>idx1) and (idx4<>idx2) and (idx4<>idx3) // 加入一個(gè)元素
then tmpStr:=tmpStr+IntToStr(Value[idx4])+' ';
Memo1.Lines.Add(tmpStr);
end;
end;
這個(gè)解是十選三,然后顯示剩下的七個(gè),是不是有點(diǎn)意思呢?
以上加入元素的判斷可以改寫為:
if ((idx1+100)*(idx2+100)*(idx3+100) mod (idx4+100) >0 )
請(qǐng)?bào)w會(huì)一下同余理論的運(yùn)用,這里利用了101到110這十個(gè)數(shù)中任一個(gè)數(shù)都不被其它三個(gè)數(shù)的乘積整除的特性
解法三、
以上兩解也可用集合來(lái)實(shí)現(xiàn)。
再想想,以上兩解都是用了多重循環(huán),必須定義多個(gè)循環(huán)變量,通用性似乎差了點(diǎn)。
觀察這些循環(huán)(尤其是解一),形式是何等的一致!
也許諸位已經(jīng)想到我要用遞歸調(diào)用來(lái)解決這個(gè)問(wèn)題了。
要設(shè)計(jì)遞歸,首先要確定哪些變量是必須向這個(gè)函數(shù)傳遞的,容易知道,調(diào)用時(shí)要知道當(dāng)前元素的起始下標(biāo)與終止下標(biāo),當(dāng)然還有兩個(gè)必不可少的參數(shù)就是我這個(gè)函數(shù)計(jì)算的是從多少選多少的,這樣就確定了四個(gè)參數(shù)。
還有一個(gè)要注意的地方,是遞歸何時(shí)顯示數(shù)據(jù)?顯然應(yīng)當(dāng)在求最后一個(gè)元素時(shí)。
(關(guān)于遞歸調(diào)用的一些詳細(xì)的論述,可以參看喬林的《參透Delphi/Kylix》一書或其它教材)
請(qǐng)看實(shí)現(xiàn):
全局變量
var
GIDX:array[1..20] of integer; // 記錄下標(biāo)的數(shù)組。
procedure MyRecur(Total,SelCnt,BLoc,ELoc:integer);
var
idx,jjj:integer;
tmpStr:string;
begin
if (ELoc=Total) // 終止?fàn)顟B(tài)
then begin
for idx:=BLoc to ELoc do
begin
GIDX[SelCnt+ELoc-Total]:=idx; // 注意此處應(yīng)與下面 8888處一致
tmpStr:='';
for jjj:=1 to SelCnt do tmpStr:=tmpStr+IntToStr(Value[GIDX[jjj]])+' ';
Form1.Memo1.Lines.Add(tmpStr);
end;
end
else begin
for idx:=BLoc to ELoc do
begin
GIDX[SelCnt+ELoc-Total]:=idx; // 8888
MyRecur(Total,SelCnt,idx+1,ELoc+1);
end;
end;
end;
procedure SelNumber(Total,SelCnt:integer);
begin
if (Total<1) or (Total<SELCNT)< p>
then begin
ShowMessage('數(shù)據(jù)不正確!');
Exit;
end;
MyRecur(Total,SelCnt,1,Total-SelCnt+1); // 最初第三個(gè)參數(shù)總為1
end;
使用:
procedure TForm1.Button3Click(Sender: TObject);
var
ttl,sel:integer;
begin
Memo1.Clear;
ttl:=StrToInt(Edit1.Text); // 請(qǐng)自己加上對(duì)TEdit的容錯(cuò)處理。
sel:=StrToInt(Edit2.Text);
SelNumber(ttl,sel);
end;
好了,在Edit1中輸入‘100’,在Edit2中輸入'3',執(zhí)行試試,三十多萬(wàn)行的數(shù)據(jù)不斷地滾出來(lái)了吧。
建議在計(jì)算前先估算一下共多少組合,最好不要超過(guò)10萬(wàn)。
相關(guān)推薦:
經(jīng)濟(jì)師資格證
2013年經(jīng)濟(jì)師考試時(shí)間
可不參加職稱外語(yǔ)考試的條件
廣州2013年職稱英語(yǔ)考試報(bào)名
大專生怎獲取學(xué)位、報(bào)考研究生
跨國(guó)公司需要考取那些證書
【一個(gè)組合數(shù)的求解方法】相關(guān)文章:
java集合數(shù)組的區(qū)別08-17
質(zhì)數(shù)和合數(shù)教學(xué)設(shè)計(jì)11-02
java集合數(shù)組的輸出辦法07-31
《質(zhì)數(shù)和合數(shù)》數(shù)學(xué)教案09-30
關(guān)于java集合數(shù)組的區(qū)別08-03
C語(yǔ)言遞歸函數(shù)的執(zhí)行與求解08-11
小升初數(shù)學(xué)專項(xiàng)復(fù)習(xí)之質(zhì)數(shù)與合數(shù)06-07