ARC074F Lotus Leaves
题意简述:给一个\(N*M(N,M<=100)\)的网格图,其中只有为'o'能走,给定一个起点和终点,每次可以从点\((i,j)\)跳到任意点\((i,k)(1<=k<=m)\)或点\((k,j)(1<=k<=n)\),问最少删掉多少个点可以使起点无法到达终点。
有一个非常沙雕的做法,基本会网络流的都能想到(除了我这个一开始把范围看错的沙雕),就直接拆点然后裸最小割,总共有\(2*n*m\)个点,\(2*n*m\)条边。
然后有一个稍微优秀一点的做法就是考虑一个点可以跳到其所在行与所在列,那么我们将行列连边,得到的就是一个二分图,然后跑一遍最小割就ok了,总共有\(n+m\)个点
//沙雕版
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
#define id(i,j) ((i-1)*m+j)
const int N=210,inf=1e9;
struct fk{int to,nxt,w;}e[N*N*N*2];
int head[N*N*2],cnt=1;
int dis[N*N*2],n,m,Sx,Sy,Tx,Ty,mp[N][N],S,T,ans,tot;
char s[N];
queue<int> q;
void add(int u,int v,int w){e[++cnt].to=v;e[cnt].nxt=head[u];e[cnt].w=w;head[u]=cnt;}
bool bfs(){
memset(dis,63,sizeof(dis));
dis[S]=0;q.push(S);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u],v;i;i=e[i].nxt)
if(e[i].w&&dis[v=e[i].to]>dis[u]+1)
dis[v]=dis[u]+1,q.push(v);
}
return dis[T]<inf;
}
int dfs(int u,int flow){
if(u==T||!flow)return flow;
int now=0;
for(int i=head[u],v;i;i=e[i].nxt)
if(e[i].w&&dis[v=e[i].to]==dis[u]+1){
int f=dfs(v,min(flow-now,e[i].w));
e[i].w-=f;e[i^1].w+=f;now+=f;
}
if(!now)dis[u]=-1;
return now;
}
void dinic(){for(;bfs();ans+=dfs(S,inf));}
int main(){
scanf("%d%d",&n,&m);tot=n*m;
S=0;T=tot*2+1;
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++)
if(s[j]!='.'){
if(s[j]=='o'){
mp[i][j]=1;
add(id(i,j),id(i,j)+tot,1);
add(id(i,j)+tot,id(i,j),0);
}
else{
if(s[j]=='S')mp[i][j]=1,Sx=i,Sy=j;
if(s[j]=='T')mp[i][j]=1,Tx=i,Ty=j;
add(id(i,j),id(i,j)+tot,inf);
add(id(i,j)+tot,id(i,j),0);
}
}
}
add(S,id(Sx,Sy),inf);
add(id(Sx,Sy),S,0);
add(id(Tx,Ty)+tot,T,inf);
add(T,id(Tx,Ty)+tot,0);
if(Sx==Tx||Sy==Ty){puts("-1");return 0;}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(mp[i][j]){
for(int k=1;k<=n;k++)
if(k!=i&&mp[k][j])
add(id(i,j)+tot,id(k,j),inf),add(id(k,j),id(i,j)+tot,0);
for(int k=1;k<=m;k++)
if(k!=j&&mp[i][k])
add(id(i,j)+tot,id(i,k),inf),add(id(i,k),id(i,j)+tot,0);
}
}
dinic();
printf("%d\n",ans);
}
//优秀版
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=510,inf=1e9;
struct fk{int to,nxt,w;}e[200010];
int head[N],cnt=1;
int dis[N],n,m,Sx,Sy,Tx,Ty,S,T,ans;
char s[N][N];
queue<int> q;
void add(int u,int v,int w){e[++cnt].to=v;e[cnt].nxt=head[u];e[cnt].w=w;head[u]=cnt;}
bool bfs(){
memset(dis,63,sizeof(dis));
dis[S]=0;q.push(S);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u],v;i;i=e[i].nxt)
if(e[i].w&&dis[v=e[i].to]>dis[u]+1)
dis[v]=dis[u]+1,q.push(v);
}
return dis[T]<inf;
}
int dfs(int u,int flow){
if(u==T||!flow)return flow;
int now=0;
for(int i=head[u],v;i;i=e[i].nxt)
if(e[i].w&&dis[v=e[i].to]==dis[u]+1){
int f=dfs(v,min(flow-now,e[i].w));
e[i].w-=f;e[i^1].w+=f;now+=f;
}
if(!now)dis[u]=-1;
return now;
}
void dinic(){for(;bfs();ans+=dfs(S,inf));}
int main(){
scanf("%d%d",&n,&m);S=0;T=n+m+1;
for(int i=1;i<=n;i++)
scanf("%s",s[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(s[i][j]=='S')Sx=i,Sy=j;
else if(s[i][j]=='T')Tx=i,Ty=j;
else if(s[i][j]=='o')add(i,j+n,1),add(j+n,i,0),add(j+n,i,1),add(i,j+n,0);
if(Sx==Tx||Sy==Ty){puts("-1");return 0;}
add(S,Sx,inf);add(Sx,S,0);
add(S,Sy+n,inf);add(Sy+n,S,0);
add(Tx,T,inf);add(T,Tx,0);
add(Ty+n,T,inf);add(T,Ty+n,0);
dinic();
printf("%d\n",ans);
}