启发式搜索题目,裸的A*算法。

启发式搜索中要选估价函数h,h函数必须满足h[i]<=到目标节点的实际距离,且在保证结果正确的情况下,h选得越大越好。广度优先搜索就是输在了估价函数上,它是一种特殊的启发式搜索,只不过启发函数为0罢了,所以广度优先搜索没有什么优化的余地。

根据上述要求,我选择的估价函数是这个点目标的距离。

维护一个优先队列,每次选择一个h[i]+dist[i]最小的节点进行扩展。

当目标n被访问k次时,这时候dist[n]就是答案。

代码:

Program POJ2449;//By_Thispoet
Const
	maxn=1000;
	maxm=100000;
Var
	i,j,k,m,n,p,q,s,t,o,head,tail	:Longint;
	h								:Array[1..maxn]of Int64;
	v								:Array[1..maxn]of Boolean;
	pre,other,last,data,pr,ot,la	:Array[1..maxm*2]of Int64;
	seq,sd							:Array[1..maxm*50]of Int64;

Procedure Down(i:Longint);
var j:Longint;
begin
	while (i<<1)<=tail do
		begin
			j:=i<<1;
			if (j<tail)and(sd[j+1]+h[seq[j+1]]<sd[j]+h[seq[j]]) then inc(j);
			if sd[i]+h[seq[i]]>sd[j]+h[seq[j]] then
				begin
					seq[i]:=seq[i] xor seq[j];
					seq[j]:=seq[i] xor seq[j];
					seq[i]:=seq[i] xor seq[j];
					sd[i]:=sd[i] xor sd[j];
					sd[j]:=sd[i] xor sd[j];
					sd[i]:=sd[i] xor sd[j];
					i:=j;
				end else break;
		end;
end;


Procedure Up(i:Longint);
var j:Longint;
begin
	while i>1 do
		begin
			j:=i>>1;
			if sd[i]+h[seq[i]]<sd[j]+h[seq[j]] then
				begin
					seq[i]:=seq[i] xor seq[j];
					seq[j]:=seq[i] xor seq[j];
					seq[i]:=seq[i] xor seq[j];
					sd[i]:=sd[i] xor sd[j];
					sd[j]:=sd[i] xor sd[j];
					sd[i]:=sd[i] xor sd[j];
					i:=j;
				end else break;
		end;
end;


Procedure Spfa_h(i:Longint);
begin
	head:=0;tail:=1;seq[tail]:=i;
	v[i]:=true;
	while head<tail do
		begin
			inc(head);
			i:=seq[head];
			j:=la[i];
			while j<>0 do
				begin
					k:=ot[j];
					if h[k]>h[i]+data[j] then
						begin
							if not v[k] then
								begin
									v[k]:=true;
									inc(tail);seq[tail]:=k;
								end;
							h[k]:=h[i]+data[j];
						end;
					j:=pr[j];
				end;
			v[i]:=false;
		end;
	if h[s]>(maxlongint<<2)then
		begin
			writeln(-1);
			halt;
		end;
end;


Procedure Spfa_d(i:Longint);
begin
	o:=0;
	tail:=1;seq[1]:=i;sd[i]:=0;
	while (tail>0)and(tail<maxm*45)do
		begin
			i:=seq[1];
			if i=t then
				begin
					inc(o);
					if o=p then
						begin
							writeln(sd[1]);
							halt;
						end;
				end;
			j:=last[i];
			while j<>0 do
				begin
					k:=other[j];
					inc(tail);
					seq[tail]:=k;
					sd[tail]:=sd[1]+data[j];
					Up(tail);
					j:=pre[j];
				end;
			seq[1]:=seq[1] xor seq[tail];
			seq[tail]:=seq[1] xor seq[tail];
			seq[1]:=seq[1] xor seq[tail];
			sd[1]:=sd[1] xor sd[tail];
			sd[tail]:=sd[1] xor sd[tail];
			sd[1]:=sd[1] xor sd[tail];
			dec(tail);
			if tail>0 then Down(1);
		end;
end;


BEGIN

	readln(n,m);
	for i:=1 to m do
		begin
			readln(p,q,j);
			inc(k);
			pre[k]:=last[p];last[p]:=k;other[k]:=q;data[k]:=j;
			pr[k]:=la[q];la[q]:=k;ot[k]:=p;
		end;

	readln(s,t,p);
	if s=t then inc(p);

	fillchar(h,sizeof(h),127);
	h[t]:=0;
	Spfa_h(t);

	Spfa_d(s);

	writeln(-1);

END.