【bzoj1066】【SCOI2007】蜥蜴
题目描述
在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。
每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个石柱上。
输入
输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石柱的初始状态,0表示没有石柱,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。
输出
输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。
样例输入
5 8 2 00000000 02000000 00321100 02000000 00000000 ........ ........ ..LLLL.. ........ ........
样例输出
1
题解
最大流。
考虑到柱子之间可以相互跳,于是要拆点。把一个点拆成入点和出点,入点出点之间连流量为柱子高度的边。
建立超级源点,向每个蜥蜴连流量为 1 的边。
建立超级汇点,向可以走出格子的点连流量为 inf 的边。
可以相互到达的柱子之间连 inf 的边。
跑最大流。
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=20+10; const int inf=2e9; int r,c,dd,s=0,t=801,ru[1000],chu[1000],d[1000],maxflow,x,tot; int fir[1000],nex[100000],to[100000],wi[100000],ecnt; char high[maxn][maxn],Map[maxn][maxn]; bool p[800+50][800+50]; int getid(int x,int y){return (x-1)*c+y;} void add(int u,int v,int w){ nex[ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;wi[ecnt++]=w; } queue<int> q; int bfs(){ memset(d,0,sizeof(d)); d[s]=1; q.push(s); while(!q.empty()){ int u=q.front();q.pop(); for(int e=fir[u];~e;e=nex[e]){ int v=to[e]; if(wi[e]&&!d[v]){ d[v]=d[u]+1; q.push(v); } } } return d[t]; } int dfs(int u,int flow){ if(u==t) return flow; if(d[u]>=d[t]) return 0; for(int e=fir[u];~e;e=nex[e]){ int v=to[e]; if(wi[e]&&d[v]==d[u]+1&&(x=dfs(v,min(flow,wi[e])))){ wi[e]-=x; wi[e^1]+=x; return x; } } return 0; } template<typename T>inline void read(T &aa){ ll ff=1;char cc=getchar();aa=0; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc<='9'&&cc>='0') aa=aa*10+cc-48,cc=getchar(); aa*=ff; } int main(){ read(r),read(c),read(dd); for(int i=1;i<=r;i++) cin>>high[i]+1; for(int i=1;i<=r;i++) cin>>Map[i]+1; memset(fir,-1,sizeof(fir)); for(int i=1;i<=r;i++) for(int j=1;j<=c;j++){ int id=getid(i,j); ru[id]=id;chu[id]=id+400; if(Map[i][j]=='L') add(s,ru[id],1),add(ru[id],s,0),tot++; if(i<=dd||j<=dd||(r-i+1<=dd)||(c-j+1<=dd)) add(chu[id],t,inf),add(t,chu[id],0); if(high[i][j]-48==0) continue; add(ru[id],chu[id],high[i][j]-48); add(chu[id],ru[id],0); } for(int i=1;i<=r;i++) for(int j=1;j<=c;j++){ for(int ii=1;ii<=r;ii++) for(int jj=1;jj<=c;jj++){ if(i==ii&&j==jj) continue; int id1=getid(i,j); int id2=getid(ii,jj); if(p[id1][id2]) continue; if((ii-i)*(ii-i)+(jj-j)*(jj-j)<=dd*dd){ add(chu[id1],ru[id2],inf); add(ru[id2],chu[id1],0); add(chu[id2],ru[id1],inf); add(ru[id1],chu[id2],0); } p[id1][id2]=p[id2][id1]=true; } } while(bfs()) while(dfs(s,inf)) maxflow+=x; cout<<tot-maxflow; return 0; }