最初版完成!
TBuffer类的代码请看 http://www.delphibbs.com/delphibbs/dispq.asp?lid=968511
功能:穷举所有可能的组合方案
type
IAA=array of array of Integer;
function GetBallOnWeight(ColorNum,WeightNum:Integer;Balls:IAA;
GetNum:array of Integer):Integer;
var
ColorBallNum, //指定的颜色已取得的球数
WeightBallNum:array of Integer;
//指定的重量已取得的球数
Solution, //解决方案数组,结构同Balls --它和Balls始终保持互补关系,此消彼涨
BallPos:IAA;
//记录球的位置,用于穷举
BindBallStack:TStack;
WeightMaps,
WieghtColorNumArray:IAA;
//重量覆盖表 --针对映射之后的WeightMap
Buffer:TBuffer;
procedure UseBall(Ci,Wi:Integer);
begin
Dec(Balls[Ci][Wi]);
Inc(Solution[Ci][Wi]);
BallPos[Ci][WeightBallNum[Wi]]:=Wi;
Inc(WeightBallNum[Wi]);
Inc(ColorBallNum[Ci]);
end;
procedure UnuseBall(Ci,Wi:Integer);
begin
Inc(Balls[Ci][Wi]);
Dec(Solution[Ci][Wi]);
Dec(WeightBallNum[Wi]);
Dec(ColorBallNum[Ci]);
end;
procedure GetBallLevel(Level:Integer;WeightMapNum:Integer);
var
WeightMap,
WeightCover:array of Integer;
BindCount:Integer;
//在此层中绑定的球数
function ValidCheck:Boolean;
//合法性检查
var
vi,vj,vs:Integer;
begin
Result:=false;
WeightCover:=@WieghtColorNumArray[Level][0];
FillChar(WeightCover[0],WeightNum*SizeOf(Integer),0);
for vi:=0 to WeightMapNum-1do
begin
vs:=0;
for vj:=Level to ColorNum-1do
if Balls[vj][WeightMap[vi]]>0 then
Inc(vs);
if (vs=0) and (WeightBallNum[WeightMap[vi]]=0) then
exit;
WeightCover[vi]:=vs;
end;
Result:=true;
end;
function TrimWeight:Boolean;
var
i,j,MapW,k,OldMapNum:Integer;
NewWeightMap:array of Integer;
b:Boolean;
begin
Result:=true;
NewWeightMap:=@WeightMaps[Level+1][0];
k:=0;
OldMapNum:=WeightMapNum;
for i:=0 to OldMapNum-1do
begin
MapW:=WeightMap;
b:=true;
if (WeightCover=1) and (WeightBallNum[MapW]=0) then
begin
//发现了一个必须填补的重量空缺
Result:=false;
for j:=Level to ColorNum-1do
if Balls[j][MapW]>0 then
begin
UseBall(j,MapW);
BindBallStack.Push(Pointer((j shl 16) or MapW));
//高位Color,低位重量
Inc(BindCount);
if Balls[j][MapW]=0 then
b:=false;
Result:=true;
break;
end;
if not Result then
exit;
end;
if b then
begin
NewWeightMap[k]:=WeightMap;
Inc(k);
end;
end;
WeightMap:=@NewWeightMap[0];
WeightMapNum:=k;
end;
procedure UnbindAll;
//退回所有在这一层中使用的球
var
i,m:Integer;
begin
for i:=0 to BindCount-1do
begin
m:=Integer(BindBallStack.Pop);
UnuseBall(m shr 16,m and $0000FFFF);
end;
end;
procedure PN(M:Integer;StartFromZero:Boolean=false);
var //计算第Level种颜色的球中,第M个的可能位置
i,s,w:Integer;
function WeightInMap(Wi:Integer):Integer;
begin
//在重量映射表中寻找重量Wi所处的位置
Result:=0;
while WeightMap[Result]<>Wido
Inc(Result);
end;
begin
if M=GetNum[Level] then
begin
GetBallLevel(Level+1,WeightMapNum);
exit;
end;
if StartFromZero then
s:=0
else
s:=WeightInMap(BallPos[Level][M-1]);
//起始重量不能比前面的相同颜色的球小
for i:=s to WeightMapNum-1do
begin
w:=WeightMap;
if Balls[Level][w]>0 then
begin
UseBall(Level,w);
PN(M+1);
UnuseBall(Level,w);
end;
end;
end;
procedure OutputResult;
var
i,j:Integer;
mstr:String;
begin
mstr:='';
for i:=0 to WeightNum-1do
begin
for j:=0 to ColorNum-1do
mstr:=mstr+IntToStr(Solution[j])+#9;
mstr:=mstr+#13#10;
end;
mstr:=mstr+#13#10;
Buffer.WriteBuf(@mstr[1],Length(mstr));
end;
begin
WeightMap:=@WeightMaps[Level][0];
if not ValidCheck then
exit;
if Level=ColorNum then
begin
Inc(Result);
OutputResult;
exit;
end;
BindCount:=0;
if not TrimWeight then
begin
UnbindAll;
exit;
end;
PN(ColorBallNum[Level],true);
UnbindAll;
end;
var
i,j,s:Integer;
begin
Result:=0;
SetLength(ColorBallNum,ColorNum);
FillChar(ColorBallNum[0],ColorNum*SizeOf(Integer),0);
//初始化颜色-球数表
SetLength(WeightBallNum,WeightNum);
FillChar(WeightBallNum[0],WeightNum*SizeOf(Integer),0);
//初始化重量-球数表
SetLength(Solution,ColorNum);
for i:=0 to ColorNum-1do
//初始化解决方案表
begin
SetLength(Solution,WeightNum);
FillChar(Solution[0],WeightNum*SizeOf(Integer),0);
end;
SetLength(WeightMaps,ColorNum+1);
for i:=0 to ColorNumdo
//一次性分配重量映射表空间
SetLength(WeightMaps,WeightNum);
for i:=0 to WeightNum-1do
//初始化最底层的重量映射表
WeightMaps[0]:=i;
SetLength(WieghtColorNumArray,ColorNum+1);
for i:=0 to ColorNumdo
//一次性分配重量覆盖表空间
SetLength(WieghtColorNumArray,WeightNum);
SetLength(BallPos,ColorNum);
for i:=0 to ColorNum-1do
begin
s:=0;
for j:=0 to WeightNum-1do
Inc(s,Balls[j]);
SetLength(BallPos,s);
end;
Buffer:=TBuffer.Create;
BindBallStack:=TStack.Create;
GetBallLevel(0,WeightNum);
BindBallStack.Free;
Form1.Memo1.Text:=Buffer.AsString;
Buffer.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Balls:IAA;
GetNum:array of Integer;
i,j,CNum,WNum:Integer;
begin
CNum:=SpinEdit1.Value;
//颜色数,这里为3
WNum:=SpinEdit2.Value;
//重量数,这里为4
SetLength(Balls,CNUm);
for i:=0 to CNum-1do
SetLength(Balls,WNum);
SetLength(GetNum,CNum);
with StringGrid1do
begin
for i:=0 to CNum-1do
for j:=0 to WNum-1do
Balls[j]:=StrToIntDef(Cells[i+1,j+1],0);
for i:=0 to CNum-1do
GetNum:=StrToIntDef(Cells[i+1,WNum+1],0);
end;
Caption:=IntToStr(GetBallOnWeight(CNum,WNum,Balls,GetNum));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
DrawGridTitle;
with StringGrid1do
begin
Cells[1,1]:='1';
Cells[2,1]:='0';
Cells[3,1]:='0';
Cells[1,2]:='2';
Cells[2,2]:='3';
Cells[3,2]:='1';
Cells[1,3]:='0';
Cells[2,3]:='2';
Cells[3,3]:='4';
Cells[1,4]:='2';
Cells[2,4]:='0';
Cells[3,4]:='1';
Cells[1,5]:='2';
Cells[2,5]:='1';
Cells[3,5]:='3';
end;
end;
procedure TForm1.DrawGridTitle;
var
i:Integer;
begin
with StringGrid1do
begin
for i:=1 to ColCount-1do
Cells[i,0]:='C'+IntToStr(i);
for i:=1 to RowCount-2do
Cells[0,i]:='W'+IntToStr(i);
Cells[0,RowCount-1]:='Num';
end;
end;
Result: (共10个)
1 0 0
1 1 1
0 0 1
0 0 1
1 0 0
1 1 0
0 0 2
0 0 1
1 0 0
1 0 1
0 1 1
0 0 1
1 0 0
1 0 0
0 1 2
0 0 1
1 0 0
0 1 1
0 0 2
1 0 0
1 0 0
0 1 1
0 0 1
1 0 1
1 0 0
0 1 0
0 0 3
1 0 0
1 0 0
0 1 0
0 0 2
1 0 1
1 0 0
0 0 1
0 1 2
1 0 0
1 0 0
0 0 1
0 1 1
1 0 1
通过增强 function ValidCheck:Boolean;
//合法性检查 过程的判断能力,可以做到将回溯
控制在一层以内。