bzoj 1066: [SCOI2007]蜥蜴
题目链接
题解
对于每块石头拆点限流为高度
限制跳跃次数
对于能跳出去的石头的连接汇点容量为INF
源点连接青蛙容量为1
对于互相能到达的点建立容量为INF的边
求出最大流为做多逃出数
答案为青蛙数-最大流
代码
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#define INF 0x7fffffff
using std::queue;
const int maxn=1010;
struct node {
int v,next,flow;
}edge[maxn*50];int num=1;
int r,c,d,S,T,cur[maxn],head[maxn],lev[maxn];
char s[31];
int mp[31][31];
void add_edge(int u,int v,int flow) {
edge[++num].v=v;edge[num].flow=flow;edge[num].next=head[u];head[u]=num;
edge[++num].v=u;edge[num].flow=0;edge[num].next=head[v];head[v]=num;
}
double calc_dis(int x1,int y1,int x2,int y2) {return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}
int calc_pos(int x,int y,int add) {return (x-1)*c+y+r*c*add;}
bool judge(int x,int y) {return x<=d||r-x<d||y<=d||c-y<d;}
bool spfa() {
memset(lev,-1,sizeof lev);
memcpy(cur,head,sizeof head);
queue<int>que;
que.push(S);lev[S]=0;
while(!que.empty()) {
int u=que.front();que.pop();
for(int i=head[u];i;i=edge[i].next) {
int v=edge[i].v;
if(edge[i].flow>0&&lev[v]<0) {
lev[v]=lev[u]+1;que.push(v);
}
}
}
if(lev[T]!=-1)return true;
else return false;
}
int dfs(int now,int flow) {
if(now==T)return flow;
int rest=0,delta;
for(int &i=cur[now];i;i=edge[i].next) {
int v=edge[i].v;
if(lev[v]==lev[now]+1&&edge[i].flow>0) {
delta=dfs(v,std::min(flow-rest,edge[i].flow));
if(delta) {
edge[i].flow-=delta;
edge[i^1].flow+=delta;
rest+=delta;if(rest==flow)break;
}
}
}
if(rest==flow)lev[now]=-1;
return rest;
}
int dinic() {
int ret=0;
while(spfa())
ret+=dfs(S,INF);
return ret;
}
int main(){
int cnt=0;
scanf("%d%d%d",&r,&c,&d); T=2*r*c+1;
for(int i=1;i<=r;i++){
scanf("%s",s+1);
for(int j=1;j<=c;j++) mp[i][j]=s[j]-'0';
}
for(int i=1;i<=r;i++) {
scanf("%s",s+1);
for(int j=1;j<=c;j++) {
if(s[j]=='L') cnt++,add_edge(S,calc_pos(i,j,0),1);
}
}
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
if(mp[i][j]) add_edge(calc_pos(i,j,0),calc_pos(i,j,1),mp[i][j]);
for(int x1=1;x1<=r;x1++)
for(int y1=1;y1<=c;y1++) {
if(!mp[x1][y1]) continue;
for(int x2=1;x2<=r;x2++)
for(int y2=1;y2<=c;y2++) {
if(x1==x2&&y1==y2) continue;
if(mp[x2][y2]&&calc_dis(x1,y1,x2,y2)<=d) {
add_edge(calc_pos(x1,y1,1),calc_pos(x2,y2,0),INF);
add_edge(calc_pos(x2,y2,1),calc_pos(x1,y1,0),INF);
}
}
}
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
if(judge(i,j)) add_edge(calc_pos(i,j,1),T,INF);
printf("%d",cnt-dinic());
return 0;
}