目录
显示
题目链接
https://www.luogu.org/problem/P2472
题解
我们将每个点拆成入点和出点,然后这样建立一个网络流的模型:
- 从源点向有蜥蜴的点连一条流量为 \(1\) 的边,代表有一只蜥蜴;
- 一个点的入点向其出点连一条流量为 \(h_i\) 的边,代表该点能被 \(h_i\) 只蜥蜴经过;
- 如果点 \(A\) 能到达点 \(B\),就从 \(A\) 的出点向 \(B\) 的入点连一条流量为 \(\infty\) 的边。
- 能出边界的点,由其出点向汇点连一条流量为 \(\infty\) 的边。
跑一遍最大流即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
struct edge
{
int v,w,next;
}e[400005];
char ma[25][25],str[25];
int head[805],cur[805],dist[805],s,t,cnt=1;
void addedge(int u,int v,int w)
{
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt;
}
bool bfs()
{
queue<int> q;
memcpy(cur,head,sizeof(cur));
memset(dist,INF,sizeof(dist));
dist[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i;i=e[i].next)
if(e[i].w&&dist[e[i].v]>dist[u]+1)
{
dist[e[i].v]=dist[u]+1;
q.push(e[i].v);
}
}
return dist[t]!=INF;
}
int dfs(int u,int flow)
{
if(u==t)return flow;
int used=0;
for(int i=cur[u];i;i=e[i].next)
{
cur[u]=i;
int v=e[i].v;
if(e[i].w&&dist[v]==dist[u]+1)
{
int w=dfs(v,min(flow-used,e[i].w));
if(w)
{
used+=w;
e[i].w-=w;
e[i^1].w+=w;
if(used==flow)break;
}
}
}
return used;
}
int calc(int x1,int y1,int x2,int y2)
{
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
int main()
{
int r,c,d;
scanf("%d%d%d",&r,&c,&d);
s=2*r*c+1,t=2*r*c+2;
for(int i=1;i<=r;i++)
scanf("%s",ma[i]+1);
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
if(ma[i][j]!='0')
{
int numu=(i-1)*c+j;
addedge(numu,r*c+numu,ma[i][j]-'0');
addedge(r*c+numu,numu,0);
for(int k=1;k<=i;k++)
for(int l=1;k!=i?l<=c:l<j;l++)
if(ma[k][l]!='0'&&calc(i,j,k,l)<=d*d)
{
int numv=(k-1)*c+l;
addedge(r*c+numu,numv,INF);
addedge(numv,r*c+numu,0);
addedge(r*c+numv,numu,INF);
addedge(numu,r*c+numv,0);
}
if(i<=d||r+1-i<=d||j<=d||c+1-j<=d)
{
addedge(r*c+numu,t,INF);
addedge(t,r*c+numu,0);
}
}
int ans=0;
for(int i=1;i<=r;i++)
{
scanf("%s",str+1);
for(int j=1;j<=c;j++)
if(str[j]=='L')
{
int num=(i-1)*c+j;
addedge(s,num,1);
addedge(num,s,0);
ans++;
}
}
while(bfs())
ans-=dfs(s,INF);
printf("%d\n",ans);
return 0;
}