不好意思:)漏了:
对于5,5,5,在程序最后又执行了while所以又加了一次。
对于12,11,10,只考虑了11 和10便判断无解了,其实还应该判断m是否是偶数
修改如下:
var
Path: string;
function GetMinPP(m, n, v: Integer): Integer;
var
Tmp: Integer;
procedure AddPath(P: Integer);
begin
Path := Path + IntToStr(P) + ',';
end;
begin
if n > m then
// 翻有最小解的那一堆
begin
n := n + m;
m := n - m;
n := n - m;
end;
Result := -1;
if (n mod 2 = 1) and (v mod 2 = 0) or (m + n <= v) or (m*n*v <= 0) then
//无解情况返回-1
if m mod 2 = 0 then
begin
n := n + m;
m := n - m;
n := n - m;
end
else
Exit;
if n mod v = 0 then
//正好整除就很简单了
begin
Result := n div v - 1;
end
else
begin
{ 非整除情况 }
Tmp := n mod v;
//Tmp 是小于v的余数: n mod v
if ((v-Tmp) mod 2 = 0) and (n > v) then
//对于n>v时,tmp有可能直接变成0,这种情况比较特殊
begin
AddPath((Tmp + v) div 2);
Result := 1;
end
else
begin
if m < v - Tmp div 2 then
Exit;
// 本来m要翻至少v-tmp div 2 个子的,但如果m不够数,表示没有翻动的余地了,无解。
Result := 2;
if Tmp = 1 then
//tmp等于1是个很奇怪的情况,如果移n,至少需要三步
begin
if (m mod v = 0) and (m div v < 3) then
//如果移m少于三步,那移m好了
begin
Path := '';
AddPath(v);
if m div v = 2 then
AddPath(v);
Result := m div v;
Exit;
end;
AddPath(1);
//把n变成不是1,再按照一般的解法解。
Tmp := v - 1;
Inc(Result);
end;
{ 这一段是核心原理 }
if Tmp mod 2 = 0 then
// Tmp mod 2=0 表示可以只一次组合成v倍数
begin
AddPath(Tmp div 2);
AddPath(v);
//对于n<v的情况,tmp无法直接变成0,只好往上发展了,因此路径加v
end
else
if Tmp = 1 then
// 1的情况也比较特殊,可以直接减1
AddPath(v div 2 + 1)
else
begin
AddPath(v div 2);
//非1情况先把n变为偶数
AddPath(Tmp div 2 + 1);
//变成偶数就可由v-2i一次性组合成功。
end;
end;
end;
while n >= vdo
//加入大于v的部分,完成!
begin
AddPath(v);
Dec(n, v);
Inc(Result);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
m, n, v: Integer;
begin
m := StrToInt(Edit1.Text);
//m = 正面为上
n := StrToInt(Edit2.Text);
//n = 反面为上
v := StrToInt(Edit3.Text);
//v = 翻动个数
Path := '';
Button1.Caption := IntToStr(GetMinPP(m, n, v));
Edit4.Text := Path;
end;