zoukankan      html  css  js  c++  java
  • [BZOJ 1458]士兵占领(网络流)

    Description

    有一个M * N的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵。现在你的任务是要求使用最少个数的士兵来占领整个棋盘。

    Solution

    可以用上下界最小流来做,不过我觉得黄学长的这个思路也很直接

    将每行每列都看成一个点,由s向行连边,容量为可以放置的士兵数-至少放置的士兵数

                由列向t连边,容量为可以放置的士兵数-至少放置的士兵数

    然后对于每个无障碍的点,由行向列连流量为1的边

    这样跑最大流就可以得到最多可以删去多少个士兵啦

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<queue>
    #define INF 0x3f3f3f3f
    #define MAXN 105
    using namespace std;
    int s,t,m,n,k,l[MAXN],c[MAXN],la[MAXN],ca[MAXN],level[MAXN*3],head[MAXN*3],cnt=0;
    bool f[MAXN][MAXN];
    struct Node
    {
        int next,to,cap;
    }Edges[MAXN*MAXN*4];
    int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    void addedge(int u,int v,int w)
    {
        Edges[cnt].next=head[u];
        head[u]=cnt;
        Edges[cnt].to=v,Edges[cnt++].cap=w;
    }
    void insert(int u,int v,int w)
    {
        addedge(u,v,w);
        addedge(v,u,0);
    }
    queue<int>q;
    bool bfs()
    {
        memset(level,-1,sizeof(level));
        q.push(s),level[s]=0;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=head[u];~i;i=Edges[i].next)
            {
                int v=Edges[i].to;
                if(level[v]==-1&&Edges[i].cap)
                level[v]=level[u]+1,q.push(v);
            }
        }
        if(level[t]==-1)return false;
        return true;
    }
    int dfs(int u,int f)
    {
        if(u==t)return f;
        int flow=0,d;
        for(int i=head[u];~i&&flow<f;i=Edges[i].next)
        {
            int v=Edges[i].to;
            if(level[v]==level[u]+1&&Edges[i].cap)
            {
                d=dfs(v,min(f-flow,Edges[i].cap));
                flow+=d;
                Edges[i].cap-=d;
                Edges[i^1].cap+=d;
            }
        }
        if(!flow)level[u]=-1;
        return flow;
    }
    int dinic()
    {
        int res=0,d;
        while(bfs())
        {
            while(d=dfs(s,INF))
            res+=d;
        }
        return res;
    }
    int main()
    {
        memset(head,-1,sizeof(head));
        m=read(),n=read(),k=read();
        s=0,t=m+n+1;
        for(int i=1;i<=m;i++)l[i]=read(),la[i]=n;
        for(int i=1;i<=n;i++)c[i]=read(),ca[i]=m;
        for(int i=1;i<=k;i++)
        {
            int x=read(),y=read();
            la[x]--,ca[y]--;
            if(la[x]<l[x]||ca[y]<c[y]){printf("JIONG!
    ");return 0;}
            f[x][y]=1;
        }
        for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
        if(!f[i][j])insert(i,m+j,1);
        for(int i=1;i<=m;i++)insert(s,i,la[i]-l[i]);
        for(int i=1;i<=n;i++)insert(m+i,t,ca[i]-c[i]);
        printf("%d
    ",m*n-k-dinic());
        return 0;
    }
  • 相关阅读:
    LeetCode--Sudoku Solver
    LeetCode--Merge Intervals
    LeetCode--Valid Number
    LeetCode--Max Points on a Line
    1.1
    智能指针原理与简单实现(转)
    C++内存管理(转)
    算法题--扔棋子
    LeetCode--Substring with Concatenation of All Words
    线性代数与MATALB1
  • 原文地址:https://www.cnblogs.com/Zars19/p/7003109.html
Copyright © 2011-2022 走看看