首先可以把每次使用超能力交换棋子看成改变兵种,因为步兵和骑兵个数相同。所以每个兵到每个目标格的最少超能力次数是可以先spfa出来的。
天兵的位置其实并不重要,而且每用一次超能力可以用天兵让一个其他兵直达目标格(就是天兵先到那里,然后交换)。
所以每次二分超能力次数lim,然后对距离<=lim的边求最大匹配ans,若ans+lim>=2*k,那么lim就是合法的。
代码:
type
node=record
x,y:longint;
e:boolean;
end;
edge=^edgenode;
edgenode=record
t:longint;
next:edge;
end;
var
m,n,k,t,i,j,r,tot:longint;
g:node;
pl,goal:array[0..110]of node;
h,mp:array[0..110,0..110]of longint;
dist:array[0..110,0..110,false..true]of longint;
visit:array[0..110,0..110,false..true]of boolean;
vis2:array[0..110]of boolean;
link:array[0..110]of longint;
dl:array[0..11000]of node;
ax:array[1..4]of longint=(0,0,-1,1);
ay:array[1..4]of longint=(-1,1,0,0);
procedure incc(var x:longint);
begin
inc(x);
if x>10100 then dec(x,10100);
end;
function pd(x,y:longint;b:boolean):longint;
begin
if ((not b)and(x<y))or(b and (x>y)) then exit(1)
else exit(0);
end;
function min(x,y:longint):longint;
begin
if x>y then exit(y)
else exit(x);
end;
procedure spfa(s:node);
var
head,tail,i,j,o:longint;
v,u:node;
begin
for i:=1 to n do
for j:=1 to m do
begin dist[i,j,false]:=n*m; dist[i,j,true]:=n*m; end;
head:=1;
tail:=1;
dl[1]:=s;
dist[s.x,s.y,s.e]:=0;
visit[s.x,s.y,s.e]:=true;
while head<>tail+1 do
begin
v:=dl[head];
for i:=1 to 4 do
begin
u.x:=v.x+ax[i];
u.y:=v.y+ay[i];
u.e:=v.e;
if (u.x<=0)or(u.x>n)or(u.y<=0)or(u.y>m) then continue;
o:=pd(h[u.x,u.y],h[v.x,v.y],v.e);
if o=1 then u.e:=not v.e;
if dist[u.x,u.y,u.e]>dist[v.x,v.y,v.e]+o then
begin
dist[u.x,u.y,u.e]:=dist[v.x,v.y,v.e]+o;
if visit[u.x,u.y,u.e]=false then
begin
incc(tail);
dl[tail]:=u;
visit[u.x,u.y,u.e]:=true;
end;
end;
end;
visit[v.x,v.y,v.e]:=false;
incc(head);
end;
end;
function pipei(x,lim:longint):boolean;
var
i:longint;
begin
for i:=1 to tot do
if (mp[x,i]<=lim)and(vis2[i]=false) then
begin
vis2[i]:=true;
if (link[i]=-1)or(pipei(link[i],lim)) then begin link[i]:=x; exit(true); end;
end;
exit(false);
end;
function check(lim:longint):boolean;
var
i,ans:longint;
begin
for i:=1 to tot do
link[i]:=-1;
ans:=0;
for i:=1 to 2*k do
begin
fillchar(vis2,sizeof(vis2),false);
if pipei(i,lim) then inc(ans);
end;
exit(ans+lim>=2*k);
end;
procedure erf;
var
l,r,mid:longint;
begin
l:=0;
r:=2*k;
while l<r do
begin
mid:=(l+r)div 2;
if check(mid) then r:=mid
else l:=mid+1;
end;
writeln(r);
end;
begin
readln(n,m,k,t);
for i:=1 to 2*k+1 do
with pl[i] do
begin
read(x,y);
e:=(i>k);
end;
tot:=0;
for i:=1 to t do
begin
read(g.x,g.y,r);
for j:=1 to r do
begin
inc(tot);
goal[tot]:=g;
end;
end;
for i:=1 to n do
for j:=1 to m do
read(h[i,j]);
for i:=1 to 2*k do
begin
spfa(pl[i]);
for j:=1 to tot do mp[i,j]:=min(dist[goal[j].x,goal[j].y,false],dist[goal[j].x,goal[j].y,true]);
end;
erf;
end.