以前做过一道类似的题目:
\[\text JZOJ\ 5948\]
小 \(X\) 的国家正在遭受袭击,必须抽调一些魂师上前线增援。
到前线用时最短的路上有一条宽度为 \(N\) 米的河,而前来增援的魂师每飞行 \(L\) 米就必须在一片荷叶上休息一下,才能够继续飞行。当然,魂师们也可以选择没飞够 \(L\) 米就先休息一下,但不能一次飞超过 \(L\) 米。
距离河的一侧距离为 \(i\) 的荷叶共有 \(Ai\) 片,每片荷叶在有魂师停于上方休息后, 就会沉入水底,不能够再供其他魂师休息。
现在小 \(X\) 想要知道,至多有多少名魂师能够抵达前线。
条件
- 有一定的跳跃距离
- 每一个荷叶有一定的跳跃次数
那就很简单了吗,每一个荷叶往它的最大跳跃距离连边然后跑最大流。
然后会错。
仔细一看要拆点,因为荷叶要限制自己 (并不是什么裂点还有什么乱七八糟的东西,不懂的可以翻阅我的博客)
然后 \(80\) 分,仔细看数据: 对于 \(100\)% 的数据,\(1≤L<N≤10^5\),\(0≤Ai≤10^4\)。
最大流瞬间咕咕,需要 \(DP\)。
这道题就是上面那道题的加强版,变成了二维。然而 \(2007\) 年的省选是那么的水。
按往常一样先画图,再连边 : (下面是一个九宫格版的数据)
要注意是距离为 \(d\) ! 然后要搞懂求距离小于 \(d\) 的公式 (没仔细看被刷 低 \(AC\) 率了)
然后就跑 \(ISAP\) 就好啦!
// luogu-judger-enable-o2
Uses math;
var
value,reach,next,from:array[-1..210000] of longint;
id:array[-1..41,-1..41,1..2] of longint;
gap,dis,cnt:array[-1..81000] of longint;
d,n,m,l,r,k,i,j,sum,tot,sink,source,number,matrix,maxflow,lizard:longint;
s:ansistring;
procedure add(l,r,sum:longint);
begin
inc(tot); from[tot]:=l; reach[tot]:=r; value[tot]:=sum; next[tot]:=cnt[l]; cnt[l]:=tot;
inc(tot); from[tot]:=r; reach[tot]:=l; value[tot]:=8-8; next[tot]:=cnt[r]; cnt[r]:=tot;
end;
function Dfs(now,flow:longint):longint;
var i,k,mindis,ret:longint;
begin
mindis:=n-1; ret:=flow;
if now=sink then exit(flow);
i:=cnt[now];
while i<>-1 do
begin
if value[i]>0 then
begin
if dis[now]=dis[reach[i]]+1 then
begin
k:=Dfs(reach[i],min(ret,value[i]));
dec(value[i],k);inc(value[i xor 1],k);
dec(ret,k);
if dis[source]>=n then exit(flow-ret);
if ret=0 then break;
end;
mindis:=min(mindis,dis[reach[i]]);
end;
i:=next[i];
end;
if ret=flow then
begin
dec(gap[dis[now]]);
if gap[dis[now]]=0 then dis[source]:=n;
dis[now]:=mindis+1;
inc(gap[dis[now]]);
end;
exit(flow-ret);
end;
begin
filldword(cnt,sizeof(cnt) div 4,maxlongint*2+1); tot:=1;
readln(n,m,d); source:=1; sink:=(1+n*m) << 1; number:=0;
for i:=1 to n do
begin readln(s);
for j:=1 to m do
begin
inc(number); id[i,j,1]:=number << 1; id[i,j,2]:=id[i,j,1]+1;
val(s[j],matrix); add(id[i,j,1],id[i,j,2],matrix);
end;
end;
for i:=1 to n do
begin readln(s);
for j:=1 to m do if s[j]='L' then begin inc(lizard); add(source,id[i,j,1],1); end;
end;
for i:=1 to n do for j:=1 to m do if (i+d>n)or(i-d<1)or(j+d>m)or(j-d<1) then add(id[i,j,2],sink,maxlongint);
for i:=1 to n do for j:=1 to m do for l:=1 to n do for r:=1 to m do if (i-l)*(i-l)+(j-r)*(j-r)<=d*d then add(id[i,j,2],id[l,r,1],maxlongint);
n:=sink+1; gap[source]:=n;
while dis[source]<n do inc(maxflow,Dfs(source,maxlongint));
writeln(lizard-maxflow);
end.