题目大意
给你一个n*m网格图,有起点荷叶和终点荷叶,有中转荷叶,其他的格子没东西,一个荷叶可以跳到同一行或者列的另一个荷叶。问最多删掉几个中转荷叶能让起点终点不连通。如果不行输出-1.
n,m<=100
解题思路
n,m这么小直接暴力zkw最大流都过得了…
好一点的做法弄个二分图,左边行右边列,中转荷叶(i,j)那么左边i连右边j双向流量1的边。
起点终点荷叶用s和t连正无穷。
跑最大流。
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a=(a>b)?a:b)
#define cmin(a,b) (a=(a<b)?a:b)
typedef long long ll;
const int N=2e5+5,M=1e7+50,mo=1e9+7;
int pd[N],dis[N],now[N],n,m,i,j,S,T,ttt,ans;
char s[105][105];
int tt,fst[N],nxt[N],c[N],Ref[N],b[N];
void cr(int x,int y,int z,int re)
{
tt++;
b[tt]=y;
c[tt]=z;
Ref[tt]=tt+re;
nxt[tt]=fst[x];
fst[x]=tt;
}
int flow(int x,int y)
{
pd[x]=ttt;
if (x==T)
{
ans+=y;
return y;
}
for(int p=now[x];p;p=nxt[p])
if (pd[b[p]]!=ttt&&c[p]&&dis[b[p]]+1==dis[x])
{
int l=flow(b[p],min(y,c[p]));
if (l)
{
c[p]-=l;
c[Ref[p]]+=l;
now[x]=p;
return l;
}
}
return now[x]=0;
}
int change()
{
int mn=1e9;
fo(i,S,T)
if (pd[i]==ttt)
for(int p=fst[i];p;p=nxt[p])
if (pd[b[p]]!=ttt&&c[p])
cmin(mn,dis[b[p]]+1-dis[i]);
if (mn==1e9) return 0;
fo(i,S,T) if (pd[i]==ttt) dis[i]+=mn;
return 1;
}
int main()
{
freopen("t18.in","r",stdin);
//freopen("t18.out","w",stdout);
scanf("%d %d\n",&n,&m);
S=0;
T=n+m+1;
fo(i,1,n)
{
scanf("%s",s[i]+1);
fo(j,1,m)
{
if (s[i][j]=='S')
{
cr(S,i,1e9,1);
cr(i,S,0,-1);
cr(S,j+n,1e9,1);
cr(j+n,S,0,-1);
}
else if (s[i][j]=='T')
{
cr(i,T,1e9,1);
cr(T,i,0,-1);
cr(j+n,T,1e9,1);
cr(T,j+n,1e9,-1);
}
else if (s[i][j]=='o')
{
cr(i,j+n,1,1);
cr(j+n,i,1,-1);
}
}
}
ans=0;
do
{
fo(i,S,T) now[i]=fst[i];
ttt++;
while (flow(S,1e9)>0) ttt++;
}while (change());
if (ans>=1e9) ans=-1;
printf("%d",ans);
}