[arc074f]Lotus Leaves

题目大意

给你一个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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值