[LightOJ - 1330] Binary Matrix [最大流][Dinic]

A binary matrix is an m x n matrix consisting of only zeroes and ones. Now you are given m integers, ith integer indicating the summation of the values of cells in ith row. You are also given n integers, ith integer indicating the summation of the values of cells in jth column.

Your task is to generate the binary matrix. As there can be multiple solutions, we want the solution which is lexicographically smallest. To compare two solutions, we first find the cell (topmost, then leftmost) where the solutions differ; then the solution which contains 0 in that cell is lexicographically smaller. So,

001

001
010
<
100
100

010

Input
Input starts with an integer T (≤ 125), denoting the number of test cases.

Each case starts with a line containing two integers: m and n (1 ≤ m, n ≤ 50). The next line contains m integers, separated by a single space, denoting the row sums. The next line contains n integers, separated by spaces, denoting the column sum. All the integers will be between 0 and 50 (inclusive).

Output
For each case, print the case number first. Then if there is no solution, then print ‘impossible’ on the same line. Otherwise, from the next line, print m lines each having n characters denoting the binary matrix as stated above.

Sample Input
5
3 3
1 1 1
1 1 1
3 3
1 1 2
2 2 1
2 3
30 30
30 20 10
2 9
5 5
1 1 2 1 1 1 1 1 1
3 3
1 2 3
3 2 1
Sample Output
Case 1:
001
010
100
Case 2: impossible
Case 3: impossible
Case 4:
001001111
111110000
Case 5:
100
110
111

题解

先构图,取一个超级源点s和一个超级汇点t

这里写图片描述

若有答案,那么要满足

max_flow=sumx=sumy

接下来输出字典序最小的答案就行了
先科普一下矩阵字典序:从左到右,从上到下,遇到不同的元素时,元素小的矩阵字典序小

对跑完最大流的残余图我们也按顺序从左到右,从上到下执行操作

  1. 对于有流量的,尝试去掉该边,如果s->t还能增广即可去,否则不可去并记录该x-y的边
  2. 对于没有流量的,直接删除

重复上面步骤就得到字典序最小的答案了

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#define INF 0x3f3f3f3f
#define MAX_V 205
using namespace std;
typedef long long LL;

const int MAXS = 1024*1024;
char buf[MAXS],bufout[MAXS],*ch,*chout;

void read(int &x){
    for(++ch;*ch<=32;++ch);
    for(x=0;*ch>='0';++ch) x=x*10+*ch-'0';
}

void out(int x){
    if(!x) *(++chout)='0';
    else{
        char *ch0=chout,*ch1=chout+1;
        while(x){
            *(++ch0)=x%10+'0';
            x/=10;
        }
        chout=ch0;
        while(ch1<=ch0) swap(*(ch1++),*(ch0--));
    }
    *(++chout)='\n';
}

void std_init(){
    ch=buf-1;
    chout=bufout-1;
    fread(buf,1,MAXS,stdin);
}

void std_out(){
    fwrite(bufout,1,chout-bufout+1,stdout);
}

/*---------------------------------------------------------------*/

int X[MAX_V],Y[MAX_V];
int mp[MAX_V][MAX_V];

int N,M;

struct edge{int to,cap,rev;};

int lever[MAX_V],iter[MAX_V];
vector<edge> G[MAX_V];

void add_edge(int x,int y,int cost){
    G[x].push_back(edge{y,cost,G[y].size()});
    G[y].push_back(edge{x,0,G[x].size()-1});
}

void bfs(int s){
    memset(lever,-1,sizeof(lever));
    queue<int> que;
    que.push(s);
    lever[s]=0;
    while(!que.empty()){
        int v=que.front();que.pop();
        for(int i=0;i<G[v].size();i++){
            edge &e=G[v][i];
            if(lever[e.to]<0&&e.cap>0){
                lever[e.to]=lever[v]+1;
                que.push(e.to);
            }
        }
    }
}

int dfs(int v,int t,int f){
    if(v==t) return f;
//  for(int &i=iter[v];i<G[v].size();i++){
    for(int &i=iter[v];i>=0;i--){
        edge &e=G[v][i];
        if(e.cap>0&&lever[v]<lever[e.to]){
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0){
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}

int max_flow(int s,int t){
    int f,flow=0;
    while(true){
        bfs(s);
        if(lever[t]==-1) return flow;
    //  memset(iter,0,sizeof(iter));
        for(int i=0;i<=t;i++) iter[i]=G[i].size()-1;
        while(f=dfs(s,t,INF)) flow+=f;
    }
}

void slove(int T){
    const int s=0,t=N+M+1;
    for(int i=0;i<=t;i++) while(!G[i].empty()) G[i].pop_back();
    int sumx=0,sumy=0;
    for(int i=0;i<N;i++) sumx+=X[i];
    for(int i=0;i<M;i++) sumy+=Y[i];
    if(sumx!=sumy){
        printf("Case %d: impossible\n",T);
        return ;
    }

//  for(int i=N;i>0;i--) add_edge(s,i,X[i-1]);
    for(int i=1;i<=N;i++) add_edge(s,i,X[i-1]);
    for(int i=1;i<=M;i++) add_edge(i+N,t,Y[i-1]);
    for(int i=1;i<=N;i++)
        for(int j=1;j<=M;j++)
            add_edge(i,j+N,1);
    int flow=max_flow(s,t);
//  printf("%d\n",flow);
    if(sumx!=flow){
        printf("Case %d: impossible\n",T);
        return ;
    }

    printf("Case %d:\n",T);
    for(int i=1;i<=N;i++)
        for(int j=1,rev=G[i][0].rev;j<G[i].size();j++){//首元素是指向s的
        //  if(G[i][j].to<=N) continue;
            edge &e=G[i][j];
            if(e.cap==0){
                G[0][rev].cap=G[e.to][0].cap=1;
                G[e.to][e.rev].cap=0;
                bfs(s);
                if(lever[t]<0){
                    mp[i][e.to-N]=1;
                    G[0][rev].cap=G[e.to][0].cap=0;
                }
                else {
                    for(int i=0;i<=t;i++) iter[i]=G[i].size()-1;
                    dfs(s,t,INF);
                }
            }else e.cap=0;
        //  printf(j==G[i].size()-1?"%d %d\n":"%d %d|",G[i][j].to-N,G[i][j].cap);
        }

    for(int i=1;i<=N;i++)
        for(int j=1;j<=M;j++)
            printf(j==M?"%d\n":"%d",mp[i][j]);
}

int main()
{
//  freopen("C:\\Users\\chutzpah\\Desktop\\in.txt","r",stdin);
    std_init();
    int T; read(T);
    for(int t=1;t<=T;t++){
        read(N);read(M);
        memset(mp,0,sizeof(mp));
        for(int i=0;i<N;i++) read(X[i]);
        for(int i=0;i<M;i++) read(Y[i]);
        slove(t);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值