洛谷P4311 士兵占领

题目大意:

\(n*m\)的网格图和无数棋子,要求第\(i\)行至少放\(l_i\)个棋子,第\(j\)行至少放\(c_j\)个棋子,有一些格子不能放棋子,最少需要放多少个棋子?

很奇妙的想法

考虑我们在全部棋子都放下的时候最多能减去多少个棋子

套路地将每一行每一列看作一个点,源点向行连边,容量为    \(m-l_i-\)这一行不能放棋子的格子数

列向汇点连边,容量为   \(n-c_j-\)这一列不能放棋子的格子数

然后对于每个能放棋子的格子,由所在行向所在列连边,表示鸽掉这一个棋子会使得所在行和所在列的流量都\(-1\)

很妙

#include
#include
#include
#include
#include
#include
#include
using namespace std;
namespace red{
#define int long long
#define eps (1e-8)
    inline int read()
    {
        int x=0;char ch,f=1;
        for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
        if(ch=='-') f=0,ch=getchar();
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return f?x:-x;
    }
    const int N=210,inf=0x3f3f3f3f;
    int n,m,k,st,ed;
    int tx[N],ty[N];
    bool g[N][N];
    int head[N],cur[N],cnt=1;
    struct point
    {
        int nxt,to,val;
        point(){}
        point(const int &nxt,const int &to,const int &val):nxt(nxt),to(to),val(val){}
    }a[N*N];
    inline void link(int x,int y,int z)
    {
        a[++cnt]=(point){head[x],y,z};head[x]=cnt;
        a[++cnt]=(point){head[y],x,0};head[y]=cnt;
    }
    inline bool check()
    {
        for(int i=1;i<=n;++i)
        {
            if(tx[i]<0) return 0;
            if(tx[i]) link(st,i,tx[i]);
        }
        for(int i=1;i<=m;++i)
        {
            if(ty[i]<0) return 0;
            if(ty[i]) link(i+n,ed,ty[i]);
        }
        return 1;
    }
    int d[N];
    queue q;
    inline bool bfs()
    {
        for(int i=1;i<=n+m+2;++i) cur[i]=head[i],d[i]=0;
        q.push(st);d[st]=1;
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            for(int i=head[now];i;i=a[i].nxt)
            {
                int t=a[i].to;
                if(!d[t]&&a[i].val)
                {
                    d[t]=d[now]+1;
                    q.push(t);
                }
            }
        }
        return d[ed];
    }
    inline int dfs(int now,int c)
    {
        if(now==ed||!c) return c;
        int ret=c,f;
        for(int i=cur[now];i;i=a[i].nxt)
        {
            cur[now]=i;
            int t=a[i].to;
            if(d[t]==d[now]+1)
            {
                f=dfs(t,min(a[i].val,ret));
                a[i].val-=f;
                a[i^1].val+=f;
                ret-=f;
                if(!ret) return c;
            }
        }
        if(ret==c) d[now]=0;
        return c-ret;
    }
    inline int dinic()
    {
        int ret=0;
        while(bfs()) ret+=dfs(st,inf);
        return ret;
    }
    inline void main()
    {
        n=read(),m=read(),k=read();
        st=n+m+1,ed=n+m+2;
        for(int i=1;i<=n;++i) tx[i]=m-read();
        for(int i=1;i<=m;++i) ty[i]=n-read();
        for(int x,y,i=1;i<=k;++i)
        {
            x=read(),y=read();
            --tx[x];
            --ty[y];
            g[x][y]=1;
        }
        if(!check())
        {
            puts("JIONG!");
            return;
        }
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=m;++j)
            {
                if(!g[i][j]) link(i,j+n,1);
            }
        }
        printf("%lld\n",n*m-k-dinic());
    }
}
signed main()
{
    red::main();
return 0;
}

你可能感兴趣的:(洛谷P4311 士兵占领)