哪位高手老师帮助解决一个条件限制程序问题? ( 积分: 200 )

  • 主题发起人 主题发起人 okokok3721
  • 开始时间 开始时间
O

okokok3721

Unregistered / Unconfirmed
GUEST, unregistred user!
给下面组合程序加上条件限制程序:送200分再赠一个SOHU.vip收费信箱略表谢意!!
在大富翁上看到jeffrey_s,写的组合程序,很好,组号速度快。如果再加上以下限制程序就会更好了。哪位高手老师愿帮忙?
[组合程序]
procedure TForm1.Button1Click(Sender: TObject);
var
k, i1, i2, i3, i4, i5, i6, i7, v, Count: integer;
FLine: array of String[2];
FOut: array [1..7] of String[2];
FLines: TStrings;
Str: String;
begin
Count := Memo1.Lines.Count;
SetLength(FLine, Count + 1);
for k := 1 to Count do
FLine[k] := Memo1.Lines[k - 1];
k := GetTickCount;
v := 0;
FLines := TStringList.Create;
try
for i1 := 1 to Count - 6 do
begin
FOut[1] := FLine[i1];
for i2 := i1 + 1 to Count - 5 do
begin
FOut[2] := FLine[i2];
for i3 := i2 + 1 to Count - 4 do
begin
FOut[3] := FLine[i3];
for i4 := i3 + 1 to Count - 3 do
begin
FOut[4] := FLine[i4];
for i5 := i4 + 1 to Count - 2 do
begin
FOut[5] := FLine[i5];
for i6 := i5 + 1 to Count - 1 do
begin
FOut[6] := FLine[i6];
for i7 := i6 + 1 to Count do
begin
FOut[7] := FLine[i7];
inc(v);
if v < 500 then
begin
str := Format('%3s%3s%3s%3s%3s%3s%3s',
[FOut[1], FOut[2], FOut[3], FOut[4], FOut[5], FOut[6],
FOut[7]]);
FLines.Add(Str);
end;
end;
end;
end;
end;
end;
end;
end;
Memo2.Lines.Assign(FLines);
finally
FLines.Free;
end;

TButton(Sender).Caption := Format('%6d ms',[integer(GetTickCount) - k]);
Caption := IntToStr(v);
end;
我的限制条件是:

条件1 两数之差:

在所有的选7组合数组中,共有①、②、③、④、⑤、⑥、⑦七位数字。如果对这7位数取2进行组合,共有①②、①③、①④、①⑤、①⑥、①⑦、②③、②④、②⑤、②⑥、②⑦、③④、③⑤、③⑥、③⑦、④⑤、④⑥、④⑦、⑤⑥、⑤⑦、⑥⑦等21种组合。
两数之差就是上面每两位对应的数相减后的差值。
两数之差最小值为1,最大值为35。两数之差就取最小值与最大值之间的值域;如果在分析中能更精确地判断两数之差的具体值,如①②之和的值初步确定为3、4、6、8等值,便将上面数值直接填入到指定数值中。计算机自动将①②之差的值为3、4、6、8的数组找出并保留下来,把其余不符合条件的去掉。如果不能确定具体差值,就把最小值和最大值输入到相关两位数组合的最小值、最大值下面。如果什么都确定不了,就什么也不用输入。
以下面一组数字为例:
数位号:①、 ②、 ③、 ④、 ⑤、 ⑥、 ⑦
数组1:01 、 05 、06 12 13 25 29
数组2:02, 08, 12, 16, 17, 23, 25
数组3:01, 06, 07, 08, 19, 28, 36
……
数组N
上面共7位数,第一组数的第①位“1”与第②位“5”两数之差为“4” ,即“5-1=4”(注意:两数之差只能是大数减小数,即后面的数减去前面的数); 第②位的“5”与第⑦位的“29”两数之差是“24”,即“29-5=24”……以此类推。两数之差就是对七位数字中每两位数之间的差进行限定。

条件2 两数之和:
两数之和道理与两数之差一样,只不过是将两数相减变成了两数相加。两数之和最小值为3,最大值为71。两数之和就取最小值与最大值之间的数域;如果在分析中能更精确地判断两数之和的具体值,如①②之和的值初步确定为5、6,8,9等值,便将上面数值直接填入到指定数值中。计算机自动将①②之和的值为5、6、8、9的数组找出并保留下来,把其余不符合条件的去掉。如果不能确定具体和值,就把最小值和最大值输入到相关两位数组合的最小值、最大值下面。如果什么都确定不了,就什么也不用输入。

条件3 三数和:
与两数之和条件类似,三数之和是将七位数取3进行组合,即123 124 125 ……567,共有35组,三数和就是对三位数相对应的数进行相加。再以上面数组为例,123的和就是第①位+第 ②位+第③位相对应的数字之和,即“1+5+6=12,”以此类推。三数和最小值为6,最大值为105。三数和就是取最小值与最大值之间的值域;如果在分析中能更精确地判断三数和的具体值,如123之和初步确定为7、9、11 、12等值,便将上面数值直接填入到指定数值中。如果不能确定具体和值,就把最小值和最大值输入到相关两位数组合的最小值、最大值下面。如果什么都确定不了,就什么也不用输入。

条件4 四数和:
道理与三数和一样,只不是将三个数相加改成四个数相加,七位数4的组合共35组,即1234,1235……4567。四数和最小值为10,最大值为138。四数和就是取最小值与最大值之间的值域;如果在分析中能更精确地判断四数和的具体值,如1234之和初步确定为22 、23、24 、25等值,便将上面数值直接填入到指定数值中。如果不能确定具体和值,就把最小值和最大值输入到相关两位数组合的最小值、最大值下面。如果什么都确定不了,就什么也不用输入。

以上4个条件我是用STRINGGRID组件,条件显示结构如下:

最小值 最大值 指定数值(总数控制在30个数值以内)

第1位与第2位之差 单个数据 单个数据 多个数据
第1位与第3位之差 单个数据 单个数据 多个数据
第1位与第4位之差 单个数据 单个数据 多个数据
……
第6位与第7位之差 单个数据 单个数据 多个数据
 
给下面组合程序加上条件限制程序:送200分再赠一个SOHU.vip收费信箱略表谢意!!
在大富翁上看到jeffrey_s,写的组合程序,很好,组号速度快。如果再加上以下限制程序就会更好了。哪位高手老师愿帮忙?
[组合程序]
procedure TForm1.Button1Click(Sender: TObject);
var
k, i1, i2, i3, i4, i5, i6, i7, v, Count: integer;
FLine: array of String[2];
FOut: array [1..7] of String[2];
FLines: TStrings;
Str: String;
begin
Count := Memo1.Lines.Count;
SetLength(FLine, Count + 1);
for k := 1 to Count do
FLine[k] := Memo1.Lines[k - 1];
k := GetTickCount;
v := 0;
FLines := TStringList.Create;
try
for i1 := 1 to Count - 6 do
begin
FOut[1] := FLine[i1];
for i2 := i1 + 1 to Count - 5 do
begin
FOut[2] := FLine[i2];
for i3 := i2 + 1 to Count - 4 do
begin
FOut[3] := FLine[i3];
for i4 := i3 + 1 to Count - 3 do
begin
FOut[4] := FLine[i4];
for i5 := i4 + 1 to Count - 2 do
begin
FOut[5] := FLine[i5];
for i6 := i5 + 1 to Count - 1 do
begin
FOut[6] := FLine[i6];
for i7 := i6 + 1 to Count do
begin
FOut[7] := FLine[i7];
inc(v);
if v < 500 then
begin
str := Format('%3s%3s%3s%3s%3s%3s%3s',
[FOut[1], FOut[2], FOut[3], FOut[4], FOut[5], FOut[6],
FOut[7]]);
FLines.Add(Str);
end;
end;
end;
end;
end;
end;
end;
end;
Memo2.Lines.Assign(FLines);
finally
FLines.Free;
end;

TButton(Sender).Caption := Format('%6d ms',[integer(GetTickCount) - k]);
Caption := IntToStr(v);
end;
我的限制条件是:

条件1 两数之差:

在所有的选7组合数组中,共有①、②、③、④、⑤、⑥、⑦七位数字。如果对这7位数取2进行组合,共有①②、①③、①④、①⑤、①⑥、①⑦、②③、②④、②⑤、②⑥、②⑦、③④、③⑤、③⑥、③⑦、④⑤、④⑥、④⑦、⑤⑥、⑤⑦、⑥⑦等21种组合。
两数之差就是上面每两位对应的数相减后的差值。
两数之差最小值为1,最大值为35。两数之差就取最小值与最大值之间的值域;如果在分析中能更精确地判断两数之差的具体值,如①②之和的值初步确定为3、4、6、8等值,便将上面数值直接填入到指定数值中。计算机自动将①②之差的值为3、4、6、8的数组找出并保留下来,把其余不符合条件的去掉。如果不能确定具体差值,就把最小值和最大值输入到相关两位数组合的最小值、最大值下面。如果什么都确定不了,就什么也不用输入。
以下面一组数字为例:
数位号:①、 ②、 ③、 ④、 ⑤、 ⑥、 ⑦
数组1:01 、 05 、06 12 13 25 29
数组2:02, 08, 12, 16, 17, 23, 25
数组3:01, 06, 07, 08, 19, 28, 36
……
数组N
上面共7位数,第一组数的第①位“1”与第②位“5”两数之差为“4” ,即“5-1=4”(注意:两数之差只能是大数减小数,即后面的数减去前面的数); 第②位的“5”与第⑦位的“29”两数之差是“24”,即“29-5=24”……以此类推。两数之差就是对七位数字中每两位数之间的差进行限定。

条件2 两数之和:
两数之和道理与两数之差一样,只不过是将两数相减变成了两数相加。两数之和最小值为3,最大值为71。两数之和就取最小值与最大值之间的数域;如果在分析中能更精确地判断两数之和的具体值,如①②之和的值初步确定为5、6,8,9等值,便将上面数值直接填入到指定数值中。计算机自动将①②之和的值为5、6、8、9的数组找出并保留下来,把其余不符合条件的去掉。如果不能确定具体和值,就把最小值和最大值输入到相关两位数组合的最小值、最大值下面。如果什么都确定不了,就什么也不用输入。

条件3 三数和:
与两数之和条件类似,三数之和是将七位数取3进行组合,即123 124 125 ……567,共有35组,三数和就是对三位数相对应的数进行相加。再以上面数组为例,123的和就是第①位+第 ②位+第③位相对应的数字之和,即“1+5+6=12,”以此类推。三数和最小值为6,最大值为105。三数和就是取最小值与最大值之间的值域;如果在分析中能更精确地判断三数和的具体值,如123之和初步确定为7、9、11 、12等值,便将上面数值直接填入到指定数值中。如果不能确定具体和值,就把最小值和最大值输入到相关两位数组合的最小值、最大值下面。如果什么都确定不了,就什么也不用输入。

条件4 四数和:
道理与三数和一样,只不是将三个数相加改成四个数相加,七位数4的组合共35组,即1234,1235……4567。四数和最小值为10,最大值为138。四数和就是取最小值与最大值之间的值域;如果在分析中能更精确地判断四数和的具体值,如1234之和初步确定为22 、23、24 、25等值,便将上面数值直接填入到指定数值中。如果不能确定具体和值,就把最小值和最大值输入到相关两位数组合的最小值、最大值下面。如果什么都确定不了,就什么也不用输入。

以上4个条件我是用STRINGGRID组件,条件显示结构如下:

最小值 最大值 指定数值(总数控制在30个数值以内)

第1位与第2位之差 单个数据 单个数据 多个数据
第1位与第3位之差 单个数据 单个数据 多个数据
第1位与第4位之差 单个数据 单个数据 多个数据
……
第6位与第7位之差 单个数据 单个数据 多个数据
 
认真看了好几遍。。发现还是很复杂,基本上不属于组合问题,而类似与图表分析问题。

不过题目好象说的不清楚,尤其是条件,输入条件:
最小最大值有什么意义?如果不确定的话可以直接 将1..36填进去?
条件意思就是说在 21 * 30(36?) 的数组,大概有 300(?)个的限定条件数据的情况下找出有限的解?
 
jeffrey_s老师:
您可能没有看明白。因为无论是30选7还是36选7,结果都是过百万的,因为买彩的人不会也不会有能力去买这些组合的,因此需要把符合一定条件的组合给找出来。比如通过一定的方法,判断条件数据,将不可能出现的组合给筛选掉。如认为下一期开奖号码,第一位数与第二位的相减的差最小值要在6以上,最大值在10以下,那么将最小值6输入最小值栏,最大值10输入最大值栏,计算就会把第一位与第二位相减差小于6,大于10的组合全部筛掉;如果判断第一位与第二位的相减的差是7或8,就把7和8输入到指定数值栏,计算机就是第一位与第二位的组合如1,8;2,9,3,10……或1,9;2,10;3,11……的组合全部给挑选出来。
 
那样的话我知道 最小最大值 的意思了。
不过把 选的7的号码 2个2个那样放 不那么直观吧,因为这样看不出 怎样能得到最终的 7 个号码吧?
 
我可以把我做的界面传给你看一下。可以告诉您的邮箱么?
 
因为显出选出的结果在另外一个组件中显示。
 
因为设置条件在一个STRINGGRID组件中设置,显示经过条件限制后的结果在另一个STRINGGRID的组件显示!
 
可以了。。。基本明白题目意思了。就是说最多 2 * 21个约束条件。。。
 
两数之差条件是21个,两数之和条件是21个,3数和条件是35个,4数和条件也是35个
不是2*21个。
 
条件加上后不知能否直接影响到程序运行速度?
 
没有详细的测试结果是否正确:
完成部分是 两数相减。
const
MaxNum = 36;
MinNum = 1;

type
TSetArray = array [1..6, 2..7] of Smallint;

procedure SgToArray(Sg: TStringGrid
var SubMin, SubMax: TSetArray);
procedure ArraryToSg(const SubMin, SubMax: TSetArray
Sg: TStringGrid);
function HandleTables(var SubMin, SubMax: TSetArray): Boolean;


procedure TForm1.Button3Click(Sender: TObject);
var
SubMin, SubMax: TSetArray;
i1, i2, i3, i4, i5, i6, i7, v: integer;
a, LowV, HighV: Array [1..7] of SmallInt;

function SetLoop(p: integer): Boolean;
var
i, v, HighP, LowP: integer;
begin
Result := false;
HighP := a[p - 1] + SubMax[p - 1, p];
if HighP > MaxNum + p - 7 then
HighP := MaxNum + p - 7;

LowP := a[1] + SubMin[1, p];
for i := 2 to p - 1 do
begin
v := a + SubMin[i, p];
if v > LowP then
begin
if v > HighP then Exit;
LowP := v;
end;
end;

HighV[p] := HighP;
LowV[p] := LowP;
Result := True;
end;
begin
SgToArray(StringGrid1, SubMin, SubMax);
if not HandleTables(SubMin, SubMax) then
begin
TButton(Sender).Caption := '数据错误';
Exit;
end;

Memo1.Lines.Clear;
v := 0;
for i1 := MinNum to MinNum + SubMax[1, 2] - 1 do
begin
a[1] := i1;
if not SetLoop(2) then Break;
for i2 := LowV[2] to HighV[2] do
begin
a[2] := i2;
if not SetLoop(3) then Break;
for i3 := LowV[3] to HighV[3] do
begin
a[3] := i3;
if not SetLoop(4) then Break;
for i4 := LowV[4] to HighV[4] do
begin
a[4] := i4;
if not SetLoop(5) then Break;
for i5 := LowV[5] to HighV[5] do
begin
a[5] := i5;
if not SetLoop(6) then Break;
for i6 := LowV[6] to HighV[6] do
begin
a[6] := i6;
if not SetLoop(7) then Break;
for i7 := LowV[7] to HighV[7] do
begin
a[7] := i7;
Inc(v);
if v < 100 then
Memo1.Lines.Add(Format('%2d %2d %2d %2d %2d %2d %2d',
[a[1], a[2], a[3], a[4], a[5], a[6], a[7]]));
end;
end;
end;
end;
end;
end;
end;
TButton(sender).Caption := Format('%d', [v]);
end;

procedure TForm1.SgToArray(Sg: TStringGrid
var SubMin, SubMax: TSetArray);
var
L, j, i, Step: integer;
begin
for j := 1 to 6 do
for i := 2 to 7 do
begin
SubMin[j, i] := 0;
SubMax[j, i] := 0;
end;

L := 0;
for Step := 1 to 6 do
for j := 1 to 7 - Step do
begin
L := L + 1;
if Sg.Cells[1, L] = '' then
SubMin[j, j + Step] := 1
else
SubMin[j, j + Step] := StrToInt(Sg.Cells[1, L]);
if StringGrid1.Cells[2, L] = '' then
SubMax[j, j + Step] := MaxNum - MinNum
else
SubMax[j, j + Step] := StrToInt(Sg.Cells[2, L]);
end;
end;

function TForm1.HandleTables(var SubMin, SubMax: TSetArray): Boolean;
var
i, j, Step, v: integer;
begin
Result := false;
for Step := 2 to 6 do //Set Min Table
for j := 1 to 7 - Step do
for i := 1 to Step - 1 do
begin
v := SubMin[j, j + i] + SubMin[j + i, j + Step];
if v > MaxNum then Exit;
if v > SubMin[j, j + Step] then
SubMin[j, j + Step] := v;
end;

for Step := 6 downto 2 do //Set Max Table
for j := 1 to 7 - Step do
begin
v := SubMax[j, j + Step] - SubMin[j, j + 1];
if v < MinNum then Exit;
if SubMax[j + 1, j + Step] > v then
SubMax[j + 1, j + Step] := v;

v := SubMax[j, j + Step] - SubMin[j + Step - 1, j + Step];
if v < MinNum then Exit;
if SubMax[j, j + Step - 1] > v then
SubMax[j, j + Step - 1] := v;
end;
Result := True;
end;
 
谢谢jeffrey_s,老师!!
  总是请教您,给您填麻烦实在不好意思!但我刚学,水平太低,实在没有办法.明天我测试一下,有什么问题我再向您请教!!
  如果您不介意的话,我想赠送您一个SOHU .VIP收费信箱,礼物太轻,实在拿不出手,但算略表我一点心意吧!
   可以把你的邮箱地址告诉我吗?我把申请SOHU VIPWY 信箱地址的卡号和密码传给你!
 
其实回答问题也算是自己的兴趣而已,并不为其他。
首先,我并不从事教师职业。。。就不必这样称呼了。
至于邮箱,我一年也没用上十次,就不要浪费了。
还有,我觉得你的程序是不应该需要这么复杂的算法的。所以也不需要太介意。

程序我下了看了,稍微不成熟,界面和说明都很复杂,不太合适。
还有好象基本的 Delphi基础技巧掌握也不扎实? 类似的可以用 Sender,Tag一次就实现的功能而不是分别写 36次。

可以在这贴写上测试结果,应该会留意到的。
 
jeffrey_s您好!

首先谢谢您对我的帮助!其实我连编程新手都称不上。我是从今年8月中旬开始学习DELPHI和PASCAL的,中间去掉回东北的半个月时间,接触程序的时间总共不超过1个半月。
我对计算机的真正认识是从去年6月份领导安排我创建威海新闻网才开始的。以前就是用计算机写一写稿,做一些简单的文字处理,上上网。到了网站后,每天都必须和电脑打交道,才认识到学好计算机的重要性。
去年下半年用半个月学会了PHOTOSHOP,还利用一周学会用dreamreaver制作网页,并设计制作了威海新闻网女性频道、生活频道两个网页模版.今年8月我把兴趣转到编程方面,开始学习DELPHI和PASCAL。可学了一段时间后,发现按照教材一步步学,进度太慢,教材上讲实例编程序,都是别人的想法,自己不感兴趣也得去学,等于按照别人的思想走,效率很不高,再加上每天对手下20余人进行业务管理指导,真正用在学编程上面的时间太少。于是想出一个办法:自己设计一个程序(以前研究、玩过一段彩票,设计一个选号程序,因为这是自己的思路,想让计算机做什么,具有什么样的功能,实现怎样的结果,自己心里很清楚),这样编出的程序,自己清楚思路,如果能看到编程高手们是如何通过DELPHI组件和PASCAL语言实现自己的思路的,等整个程序写完后,自己对程序设计与开发,编写代码实现自己的思路,便会有了一个最基本的认识,以后学起来才更有针对性,学习效率才更高。
我手下也有三个搞程序的,二个不懂DELPHI,一个姓赵的是计算机本科今年刚毕业,学过DELPHI,我就是跟他学,不懂问他。当他帮我用递归函数将36选7组合后用STRINGGRID组件显示组合结果时,因为数据量太大,显示不出来,速度也极慢。没有办法,只好让组合结果显示1000组以下,可加上一个限制条件后(条件是第一位与第二位的差为2),运行速度迅速慢了下来,30选7不加条件,用了13秒算完,加上一个条件,增加到90多秒,如果条件一多,运行效率根本不行。最后只好改算法,他对别的算法不太熟,没办法,我上网去咨询高手帮忙。最终是您帮写了一种新的组合算法。不怕您笑话,这就是我学程序的整个经历。
由于我对程序认识太浅,在程序结构设计上肯定有不适应的地方,对彩票了解不多,可能不太理解这个程序的思路。不过这个彩票程序是我自己对彩票研究三年后的成果。其中设计的条件背后的选号奥妙,也许只有我自己才会更清楚。现在PASCAL语法结构我已基本学完,但要熟练运用还需要一个比较长过程。

如果您方便的话,有时间并有兴趣帮我写代码的话,我将感激不尽。如果工作忙且没有兴趣也就算了,不过以后碰到难题,我会经常上网去请教您,您不会介意吧?!长话短说,明天测试后,有了结果,我会再向您请教!多谢了!!!

王树清
 
jeffrey_s朋友:
您好!
我今天试着看了你的加条件的程序,也许水平太低,第一次看到这么多变量,没看太懂,请我们姓赵的程序员帮助我测试一下,他说发现程序内有很多未定义的变量,费了很多劲儿,测试不下去。
不知能否将您写的程序放到我给传的界面中去,再传给我。我的信箱是okokok3721@163.com.这样我们也许会看得更清楚一些!!
多谢了!!
 

Similar threads

S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
900
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
后退
顶部