Codeforces-1913E:Matrix Problem(最小费用最大流)

E. Matrix Problem
time limit per test 1 second
memory limit per test 256 megabytes
inputstandard input
outputstandard output
You are given a matrix a, consisting of n n n rows by m m m columns. Each element of the matrix is equal to 0 0 0 or 1 1 1.

You can perform the following operation any number of times (possibly zero): choose an element of the matrix and replace it with either 0 0 0 or 1 1 1.

You are also given two arrays A A A and B B B (of length n n n and m m m respectively). After you perform the operations, the matrix should satisfy the following conditions:

  1. the number of ones in the i i i-th row of the matrix should be exactly A i A_i Ai for every i ∈ [ 1 , n ] i\in[1,n] i[1,n].
  2. the number of ones in the j j j-th column of the matrix should be exactly B j B_j Bj for every j ∈ [ 1 , m ] j\in[1,m] j[1,m].

Calculate the minimum number of operations you have to perform.

Input
The first line contains two integers n n n and m m m ( 2 ≤ n , m ≤ 50 ) (2\le n,m\le50) (2n,m50).

Then n n n lines follow. The i i i-th of them contains m m m integers a i , 1 , a i , 2 , … , a i , m   ( 0 ≤ a i , j ≤ 1 ) a_{i,1},a_{i,2},…,a_{i,m}\ (0\le a_{i,j}\le1) ai,1,ai,2,,ai,m (0ai,j1).

The next line contains n n n integers A 1 , A 2 , … , A n   ( 0 ≤ A i ≤ m ) A_1,A_2,…,A_n\ (0\le A_i\le m) A1,A2,,An (0Aim).

The next line contains m m m integers B 1 , B 2 , … , B m   ( 0 ≤ B i ≤ n ) B_1,B_2,…,B_m\ (0\le B_i\le n) B1,B2,,Bm (0Bin).

Output
Print one integer — the minimum number of operations you have to perform, or − 1 -1 1 if it is impossible.

Examples
input
3 3
0 0 0
0 0 0
0 0 0
1 1 1
1 1 1
output
3
input
3 3
1 1 1
1 1 1
1 1 1
3 2 1
1 2 3
output
3
input
2 2
0 0
0 0
1 2
0 1
output
-1

思路:最小费用最大流。从源点 S S S建一条至 i i i的容量为 A i A_i Ai费用为0的有向边,从 j j j建一条至汇点 T T T的容量为 B j B_j Bj费用为0的有向边。同时 i , j i,j i,j之间建一条 i i i j j j且容量为1费用为 a i , j ⨁ 1 a_{i,j}\bigoplus 1 ai,j1的有向边。

  1. a i , j a_{i,j} ai,j 1 1 1时,费用为0,流量流过这条边不增加费用,映射到操作代表不改变 a i , j a_{i,j} ai,j a i , j = 1 a_{i,j}=1 ai,j=1
  2. a i , j a_{i,j} ai,j 0 0 0时,费用为1,若有流量流过这条边,则增加费用,映射到操作代表将 a i , j = 0 a_{i,j}=0 ai,j=0变为 a i , j = 1 a_{i,j}=1 ai,j=1

求出最小费用最大流 c , f c,f c,f后,若答案存在则有 f = ∑ A i = ∑ B j f=\sum A_i = \sum B_j f=Ai=Bj,其中有 c c c次操作将 a i , j = 0 a_{i,j}=0 ai,j=0变为 a i , j = 1 a_{i,j}=1 ai,j=1,那么在原图中有 f − c f-c fc a i , j = 1 a_{i,j}=1 ai,j=1未发生变化,那么原图中多出来的 ∑ a i , j − ( f − c ) \sum a_{i,j}-(f-c) ai,j(fc) 1 1 1就需要变为 0 0 0
所以最终操作次数为 c + ∑ a i , j − ( f − c ) = ∑ a i , j − f + 2 × c c+\sum a_{i,j}-(f-c)=\sum a_{i,j}-f+2\times c c+ai,j(fc)=ai,jf+2×c

#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())
#define pii pair<ll,ll>
#define bit bitset<100000>
using namespace std;
const int MAX=2e6+10;
const int MOD=1e9+7;
const int INF=INT_MAX/2;
const double PI=acos(-1.0);
typedef long long ll;
struct edg{int from,to,cap,cost,rev;};
class MCMF
{
    struct node
    {
        int x,dis,flow;
        bool operator<(const node& q) const {return q.dis<dis;}
    };
private:
    int s,t;
    vector<int>h,d,v;
    vector<edg*>p;
    vector<vector<edg>>g;
private:
    void Spfa() { //worst O(n*m)
        fill(h.begin(),h.end(),INF);
        fill(v.begin(),v.end(),0);
        queue<int>q;
        q.push(s);
        h[s]=0;
        while(!q.empty())
        {
            int x=q.front();q.pop();
            v[x]=0;
            for(auto &e:g[x])
            {
                int y=e.to;
                if(!e.cap||h[y]<=h[x]+e.cost)continue;
                h[y]=h[x]+e.cost;
                if(v[y])continue;
                v[y]=1;
                q.push(y);
            }
        }
    }
    int Dijkstra(int flow) //O(m*log(n))
    {
        fill(v.begin(),v.end(),0);
        fill(d.begin(),d.end(),-1);
        fill(p.begin(),p.end(),nullptr);
        priority_queue<node> q;
        q.push({s,0,flow});
        d[s]=0;
        int ret=0;
        while(!q.empty())
        {
            auto cur=q.top();q.pop();
            int x=cur.x;
            if(d[x]!=cur.dis)continue;
            if(x==t)ret=cur.flow;
            for(auto &e:g[x])
            {
                int y=e.to;
                if(e.cap<=0)continue;
                if(d[y]!=-1&&d[y]<=d[x]+e.cost+h[x]-h[y])continue;
                d[y]=d[x]+e.cost+h[x]-h[y];
                p[y]=&e;
                q.push({y,d[y],min(cur.flow,e.cap)});
            }
        }
        return ret;
    }
public:
    explicit MCMF(int _n,int _s,int _t)
    {
        s=_s,t=_t;
        h.resize(_n);d.resize(_n);
        v.resize(_n);p.resize(_n);g.resize(_n);
    }
    void AddEdg(int from,int to,int cap,int cost) {
        g[from].push_back((edg){from,to,cap,cost,sz(g[to])});
        g[to].push_back((edg){to,from,0,-cost,sz(g[from])-1});
    }
    pii MinCostMaxFlow(int flow)
    {
//        Spfa();
        fill(h.begin(),h.end(),0);
        int mf=0,mc=0,f=0;
        while(f=Dijkstra(flow))
        {
            for(int i=0;i<sz(v);i++)h[i]+=d[i]; //update h
            for(int i=t;p[i];i=p[i]->from)      //update cap
            {
                p[i]->cap-=f;
                g[p[i]->to][p[i]->rev].cap+=f;
            }
            flow-=f;
            mf+=f;
            mc+=f*h[t];
        }
        return {mf,mc};
    }
};
int solve()
{
    int n,m,s=0,sa=0,sb=0;
    cin>>n>>m;
    MCMF t(n+m+2,0,n+m+1);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        int x;
        scanf("%d",&x);
        t.AddEdg(i,j+n,1,x^1);
        s+=x;
    }
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        sa+=x;
        t.AddEdg(0,i,x,0);
    }
    for(int i=1;i<=m;i++)
    {
        int x;
        scanf("%d",&x);
        sb+=x;
        t.AddEdg(i+n,n+m+1,x,0);
    }
    int flow,cost;
    tie(flow,cost)=t.MinCostMaxFlow(n*m);
    if(flow!=sa||flow!=sb)return puts("-1");
    return printf("%d\n",s-flow+2*cost);
}
int main()
{
    int T=1;
    //cin>>T;
    while(T--)solve();
    return 0;
}

你可能感兴趣的:(网络流,算法,最小费用最大流)