Time limit : 2sec / Memory limit : 256MB
Score : 800 points
Problem Statement
There is a pond with a rectangular shape. The pond is divided into a grid with H rows and W columns of squares. We will denote the square at the i-th row from the top and j-th column from the left by (i, j).
Some of the squares in the pond contains a lotus leaf floating on the water. On one of those leaves, S, there is a frog trying to get to another leaf T. The state of square (i, j) is given to you by a character aij, as follows:
. : A square without a leaf.
o : A square with a leaf floating on the water.
S : A square with the leaf S.
T : A square with the leaf T.
The frog will repeatedly perform the following action to get to the leaf T: “jump to a leaf that is in the same row or the same column as the leaf where the frog is currently located.”
Snuke is trying to remove some of the leaves, other than S and T, so that the frog cannot get to the leaf T. Determine whether this objective is achievable. If it is achievable, find the minimum necessary number of leaves to remove.
Constraints
2≤H,W≤100
aij is ., o, S or T.
There is exactly one S among aij.
There is exactly one T among aij.
Input
Input is given from Standard Input in the following format:
H W
a11 … a1W
:
aH1 … aHW
Output
If the objective is achievable, print the minimum necessary number of leaves to remove. Otherwise, print -1 instead.
Sample Input 1
3 3
S.o
.o.
o.T
Sample Output 1
2
Remove the upper-right and lower-left leaves.
Sample Input 2
3 4
S…
.oo.
…T
Sample Output 2
0
Sample Input 3
4 3
.S.
.o.
.o.
.T.
Sample Output 3
-1
Sample Input 4
10 10
.o…o..o.
….o…..
….oo.oo.
..oooo..o.
….oo….
..o..o….
o..o….So
o….T….
….o…..
……..oo
Sample Output 4
5
Gist
给出一个 N*M 的网格图,上面的点有的是有跳板的,又给出起点和终点。
有跳板的点可以跳到同一行或是同一列的另一个有跳板的点。
问至少移走几个跳板,能使起点走不到终点。
数据范围: 2≤N,M≤100
Solution
经典的最小割模型。
把一个点拆为两个点——一个入点和一个出点(连进来的边都连到入点,连出去的边都从出点连)。
然后每一行每一列都设置一个“源点”,并将行列中的“叶子点”与其连边(容量为正无穷)。
最后入点向出点连一条容量为 1 的边,代表移开这个点的代价为 1 。
最后跑一遍最小割即可。
Code
#include<cstdio>
#include<cctype>
using namespace std;
const int N=105,S=N*N<<1,inf=1e9;
int tot,s,t,sum,ans;
int first[S],next[S*10],en[S*10],w[S*10];
int in[N][N],out[N][N],r[N],c[N];
int dis[S],gap[S],cur[S];
char st[N][N];
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
inline int min(int x,int y)
{
return x<y?x:y;
}
inline void ins(int x,int y,int z)
{
next[++tot]=first[x];
first[x]=tot;
en[tot]=y;
w[tot]=z;
}
inline void insert(int x,int y,int z)
{
ins(x,y,z),ins(y,x,0);
}
int sap(int x,int y)
{
if(x==t) return y;
int use=0;
for(int i=cur[x];i;i=next[i])
if(w[i] && dis[x]==dis[en[i]]+1)
{
cur[x]=i;
int p=sap(en[i],min(w[i],y-use));
w[i]-=p,w[i^1]+=p,use+=p;
if(use==y || dis[s]>sum) return use;
}
cur[x]=first[x];
if(!--gap[dis[x]]) dis[s]=sum+1;
gap[++dis[x]]++;
return use;
}
int main()
{
int n=read(),m=read();
s=++tot,t=++tot;
for(int i=1;i<=n;i++)
{
scanf("%s",st[i]+1);
for(int j=1;j<=m;j++)
if(st[i][j]=='o')
{
in[i][j]=++tot;
out[i][j]=++tot;
}
}
for(int i=1;i<=n;i++) r[i]=++tot;
for(int i=1;i<=m;i++) c[i]=++tot;
gap[0]=sum=tot;
for(int i=tot=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(st[i][j]=='o')
{
insert(in[i][j],out[i][j],1);
insert(r[i],in[i][j],inf);
insert(c[j],in[i][j],inf);
insert(out[i][j],r[i],inf);
insert(out[i][j],c[j],inf);
}else
if(st[i][j]=='S')
{
insert(s,r[i],inf);
insert(s,c[j],inf);
}else
if(st[i][j]=='T')
{
insert(r[i],t,inf);
insert(c[j],t,inf);
}
for(int i=1;i<=sum;i++) cur[i]=first[i];
while(dis[s]<=sum) ans+=sap(s,inf);
printf("%d",ans>=n*m?-1:ans);
return 0;
}