征求一算法. (看来都嫌分少,这样吧再加300,一共400了) (100分)

  • 主题发起人 主题发起人 LeeChange
  • 开始时间 开始时间
Lee兄:您那个程序我看不懂,修改了一下自个的,再看看现在这个如何:
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 (m + n <= v) or (m<=0) or (n<=0) or (v<=0) then
//无解情况返回-1
Exit;
if (n mod 2 = 1) and (v mod 2 = 0) then
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
begin
while m*n <> 0do
begin
if m >= n then
begin
AddPath(v-m);
n := n + m*2 -v;
m := v - m;
end
else
begin
AddPath(n);
m := m + n*2 - v;
n := v - n;
end;
Inc(Result);
end;
Inc(Result);
Exit;
end;
//else
// 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;

if m mod v = 0 then
if m div v < Result then
begin
Result := m div v;
Path := '';
while m <> 0do
begin
AddPath(v);
Dec(m, v);
end;
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;
 
to 叶侠:
您看一下m=1, n=4, v=3的情况.
 
不严密,再看:
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 (m + n <= v) or (m<=0) or (n<=0) or (v<=0) then
//无解情况返回-1
Exit;
if (n mod 2 = 1) and (v mod 2 = 0) then
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
begin
while m*n <> 0do
begin
if m >= n then
begin
AddPath(v-m);
n := n + m*2 -v;
m := v - m;
end
else
begin
AddPath(n);
m := m + n*2 - v;
n := v - n;
end;
Inc(Result);
end;
Inc(Result);
Exit;
end;
//else
// 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,再按照一般的解法解。
if (m-v+2=v) then
begin
AddPath(0);
Exit;
end;
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;

if m mod v = 0 then
if m div v < Result then
begin
Result := m div v;
Path := '';
while m <> 0do
begin
AddPath(v);
Dec(m, v);
end;
end;
end;
 
to 叶侠:
您看一下m=1, n=8, v=6的情况.
 
吐血:
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 (m + n <= v) or (m<=0) or (n<=0) or (v<=0) then
//无解情况返回-1
Exit;
if (n mod 2 = 1) and (v mod 2 = 0) then
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) and (m>= v - Tmp div 2) then
//对于n>v时,tmp有可能直接变成0,这种情况比较特殊
begin
AddPath((Tmp + v) div 2);
Result := 1;
end
else
begin
if m < v - Tmp div 2 -1 then
begin
if n < v then
begin
while m*n <> 0do
begin
if m >= n then
begin
AddPath(v-m);
n := n + m*2 -v;
m := v - m;
end
else
begin
AddPath(n);
m := m + n*2 - v;
n := v - n;
end;
Inc(Result);
end;
end
else
begin
n := n + m;
m := n - m;
n := n - m;
Result := 3;
Path := '';
AddPath(1);
m := m + n*2 - v;
n := v - n;
if m=v then
begin
Dec(Result);
AddPath(0);
end
else
begin
AddPath((2*v-m) div 2);
AddPath(0);
end;
Exit;
end;
Inc(Result);
Exit;
end;
//else
// 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,再按照一般的解法解。
if (m-v+2=v) then
begin
AddPath(0);
Exit;
end;
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一次性组合成功。
if n<v then
AddPath(v);
end;
end;
end;

while n >= vdo
//加入大于v的部分,完成!
begin
AddPath(v);
Dec(n, v);
Inc(Result);
end;

if m mod v = 0 then
if m div v < Result then
begin
Result := m div v;
Path := '';
while m <> 0do
begin
AddPath(v);
Dec(m, v);
end;
end;
 
to to 叶侠:
您看一下m=1, n=8, v=7的情况.
 
是是,错了。
 
to LeeChange:我还是认为可以用双广。因为从全0到全1的步数是可以算出的,所以可以把两种结束条件简化为一个,也就可以用双广了。
 
to ai_player:
那样就不是最短了,而且此题数据量不大,没必要用双向.
 
看了就头痛,谢你回答我的问题,我就帮助UP一下了
 
to macrowdw:
thanks a lot.
 
你是怎么给我发的消息?是论坛提供的吗?我怎么没找到
 
to LeeChange:求出到全0的步数,也就可以知道到全1的步数,取小的那个,必定是最短。搜索的状态数最大可以达到2^255,尽管有很多状态不可能达到,我还是认为有必要进一步优化。
 
一般来说,如果目标结点状态不明确的话,是不适合用双向的。
 
从全0的状态翻到全1的状态是有规律的。所以只要知道如何从初始状态翻到全0,必然也可以根据规律推出翻到全1的方法。这样只需要把目标状态定为全0了。因为如何翻到全1是可以推出的,不需要搜索。既然现在已经只有一种目标状态了,为什么不适合双向?
 
呵呵,那请教一个问题。
逆向搜索的其始状态为什么?
探讨探讨,如果能有您的程序,就更好了。
 
逆向搜索的初始状态当然就是题目所给的初始状态了
 
呵呵,那正向搜索的初始状态呢?
期待您的程序。
 
正向的嘛,就是全0(或者全1,到底哪个更好,有没有实现判断的方法我还在想)
写程序这两天估计没时间了,我们明天开始半期考试,考差了有要被骂了
 
原来你也不好取舍呀。呵呵。
所以我才说用双向有麻烦嘛。呵呵。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
后退
顶部