uva 11082 Matrix Decompressing (最大流)

uva 11082 Matrix Decompressing

题目大意:给出一个矩阵前i列所有元素的和,和前j行所有元素的和,求这个矩阵解压以后的原型。(答案不唯一)
解题思路:先根据题目所给出的条件,求出每行每列的和。然后把每行每列都当成一个节点,设置一个超级源点连向所有行结点,容量为“该行的和减去列数”,设置一个超级汇点,使所有的列结点连向超级汇点,容量为“该列的和减去行数”,然后所有的行结点和列结点相连,容量为19。图建好了,之后求完最大流,行结点列结点对应边上的流量,就是解压后的矩阵的元素。
那么这里有一个问题,为什么上面的容量要设置成“该列的和减去行数”和“该行的和减去列数”还有“19”,是不是都少了什么?在建图之前,把矩阵中的每一个元素都减去1,所以每列减去了行数,每行减去列数。这样做的目的是为了保证最终矩阵中的每一个元素都在1~20之内。如果不作处理的话,会出现0流,不符合题目条件。所以在一开始全部减去一,流不会为负,最后输出的时候在全部都加上一,就符合了题目的条件。
>
#include <cstring>
#include <algorithm> 
#include <cmath>
#include <cstdlib>
#include <queue>
using namespace std;
typedef long long ll;
const int N = 255;
const int OF = 50;
const int FIN = 205;
const int INF = 0x3f3f3f3f;
int R, C, s, t;
int X[N], Y[N], A[N], B[N];
struct Edge{
    int from, to, cap, flow; 
};

vector<Edge> edges;
vector<int> G[FIN * 2];

void init() {
    for (int i = 0; i < FIN * 2; i++) G[i].clear();
    edges.clear();
}
void addEdge(int from, int to, int cap, int flow) {
    edges.push_back((Edge){from, to, cap, 0});
    edges.push_back((Edge){to, from, 0, 0});
    int m = edges.size();
    G[from].push_back(m - 2);
    G[to].push_back(m - 1);
} 
void input() { //建图
    for (int i = 0; i < R; i++) { //读入前i行所有元素的和
        scanf("%d", &A[i]); 
    }
    for (int i = 0; i < C; i++) { //读入前i列所有元素的和
        scanf("%d", &B[i]); 
    }
    // 为了使最终展现的矩阵元素从1 ~ 20,所以在一开始就把所有元素减1,每一行之和减C,每一列之和减R
    // 最后的结果再加上一,防止0流的出现,
    X[0] = A[0] - C;              //将前i行所有元素的和,转换为每行元素的和
    for (int i = 1; i < R; i++) {
        X[i] = A[i] - A[i - 1] - C; 
    }
    Y[0] = B[0] - R;              //将前i列所有元素的和,转换为每列元素的和
    for (int i = 1; i < C; i++) {
        Y[i] = B[i] - B[i - 1] - R;     
    }
    for (int i = 1; i <= R; i++) {
        addEdge(s, i, X[i - 1], 0);         
    }
    for (int i = 1; i <= C; i++) {
        addEdge(i + OF, t, Y[i - 1], 0);        
    }
    for (int i = 1; i <= R; i++) {
        for (int j = 1; j <= C; j++) {
            addEdge(i, j + OF, 19, 0);  
        }
    }
}

int vis[N], d[N];
int BFS() {
    memset(vis, 0, sizeof(vis));
    queue<int> Q;
    Q.push(s);
    d[s] = 0;
    vis[s] = 1;
    while (!Q.empty()) {
        int u = Q.front(); Q.pop(); 
        for (int i = 0; i < G[u].size(); i++) {
            Edge &e = edges[G[u][i]];   
            if (!vis[e.to] && e.cap > e.flow) {
                vis[e.to] = 1;  
                d[e.to] = d[u] + 1;
                Q.push(e.to);
            }
        }
    }
    return vis[t];
}

int cur[N];
int DFS(int u, int a) {
    if (u == t || a == 0) return a;
    int flow = 0, f; 
    for (int &i = cur[u]; i < G[u].size(); i++) {
        Edge &e = edges[G[u][i]];
        if (d[u] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) {
            e.flow += f;    
            edges[G[u][i]^1].flow -= f;
            flow += f;
            a -= f;
            if (a == 0) break;
        }
    }
    return flow;
}
int MF() { //dinic算法求最大流
    int ans = 0;
    while (BFS()) {
        memset(cur, 0, sizeof(cur));    
        ans += DFS(s, INF);
    }
    return ans;
}
int ans[N][N];
void output() {
    int k = MF();   
    for (int i = 0; i < edges.size(); i += 2) {
        Edge &e = edges[i];
        if (e.to < OF) continue;
        ans[e.from][e.to - (OF)] = e.flow; //记录每一段的流
    }
    for (int i = 1; i <= R; i++) {
        for (int j = 1; j <= C; j++) {
            printf("%d ", ans[i][j] + 1);       
        }   
        puts("");
    }
}
int main() {
    int T, Case = 1;
    scanf("%d", &T);
    while (T--) {
        printf("Matrix %d\n", Case++);
        scanf("%d %d", &R, &C);     
        s = 0, t = FIN;
        init();
        input();
        output();
        if (T) puts("");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值