【AtCoder Regular Contest 074 F】Lotus Leaves

最小割。

题目大意:

给定一张 $H\times W$ 的网格图,要求从一个点走到另一个点。

若你现在在 $(x,y)$,则可以走到 $(x,k)$ 或 $(k,y)$,$k$ 是任意整数。

有些格子是障碍,不能走。

现在问至少删掉多少个格子,才能使你无法走到终点。

题解:

不难想到最小割模型。

我们把非障碍点拆成两个点,中间连容量为 $1$ 的边。删掉这条边就代表删掉这个点。

然后能直接到达的点之间连边,跑最大流即可。

直接连边会连 $O(n^3)$ 条边,我们对每行、每列建一个中转点,这样就只有 $O(n^2)$ 条边了。

Code:

#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int N=1919810;
struct edge{
    int to,nxt,cap;
}e[N];
int n,m,sx,sy,tx,ty,id[105][105][2],nod,head[N],cnt=1,ans,dep[N];
int R[105],C[105],T,iter[N];
char mp[105][105];
void addedge(int u,int v,int cap=1){
    e[++cnt]=(edge){v,head[u],cap},head[u]=cnt;
    e[++cnt]=(edge){u,head[v],0},head[v]=cnt;
}
queue<int>q;
void BFS(){
    dep[0]=1;
    for(q.push(0);!q.empty();){
        int u=q.front();q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        if(e[i].cap&&!dep[e[i].to]){
            dep[e[i].to]=dep[u]+1;
            q.push(e[i].to);
        }
    }
}
int dfs(int u,int f){
    if(u==T||!f)return f;
    for(int&i=iter[u];i;i=e[i].nxt)
    if(e[i].cap&&dep[e[i].to]>dep[u]){
        int d=dfs(e[i].to,min(f,e[i].cap));
        if(d){
            e[i].cap-=d,e[i^1].cap+=d;
            return d;
        }
    }
    return 0;
}
void dinic(){
    for(;;){
        for(int i=0;i<=T;++i)dep[i]=0;
        BFS();
        if(!dep[T])break;
        for(int i=0;i<=T;++i)iter[i]=head[i];
        while(int f=dfs(0,0x3fffffff))ans+=f;
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%s",mp[i]+1);
        for(int j=1;j<=m;++j)
        if(mp[i][j]=='S')sx=i,sy=j;else
        if(mp[i][j]=='T')tx=i,ty=j;else
        if(mp[i][j]=='o'){
            id[i][j][0]=++nod,id[i][j][1]=++nod;
            addedge(nod-1,nod);
        }
    }
    if(sx==tx||sy==ty)return puts("-1"),0;
    for(int i=1;i<=n;++i)R[i]=++nod;
    for(int i=1;i<=m;++i)C[i]=++nod;
    T=++nod;
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)if(mp[i][j]=='o'){
        addedge(id[i][j][1],R[i],0x3fffffff);
        addedge(id[i][j][1],C[j],0x3fffffff);
        addedge(R[i],id[i][j][0],0x3fffffff);
        addedge(C[j],id[i][j][0],0x3fffffff);
    }
    addedge(0,R[sx],0x3fffffff),addedge(0,C[sy],0x3fffffff);
    addedge(R[tx],T,0x3fffffff),addedge(C[ty],T,0x3fffffff);
    dinic();
    printf("%d\n",ans);
    return 0;
}