Matrix Decompressing UVA - 11082

本文介绍了一种使用网络流算法解决UVA-11082矩阵解压缩问题的方法。通过建立特殊的图结构并利用最大流算法,成功还原了矩阵的原始状态。文章详细阐述了解题思路及核心代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Matrix Decompressing UVA - 11082

网络流·最大流

http://m.blog.youkuaiyun.com/article/details?id=46985575

题目大意:

给出一个矩阵前i列所有元素的和,和前j行所有元素的和,求这个矩阵解压以后的原型。(答案不唯一)

题解:

先根据题目所给出的条件,求出每行每列的和。然后把每行每列都当成一个节点,设置一个超级源点连向所有行结点,容量为“该行的和减去列数”,设置一个超级汇点,使所有的列结点连向超级汇点,容量为“该列的和减去行数”,然后所有的行结点和列结点相连,容量为19。图建好了,之后求完最大流,行结点列结点对应边上的流量,就是解压后的矩阵的元素。
那么这里有一个问题,为什么上面的容量要设置成“该列的和减去行数”和“该行的和减去列数”还有“19”,是不是都少了什么?在建图之前,把矩阵中的每一个元素都减去1,所以每列减去了行数,每行减去列数。这样做的目的是为了保证最终矩阵中的每一个元素都在1~20之内。如果不作处理的话,会出现0流,不符合题目条件。所以在一开始全部减去一,流不会为负,最后输出的时候在全部都加上一,就符合了题目的条件。

Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define D(x) cout<<#x<<" = "<<x<<"  "
#define E cout<<endl
using namespace std;

const int N = 55;
const int M = N*N+2*N;
const int INF = 0x3f3f3f3f;

int n,m,S,T;
int hang[N], lie[N], tp[N];

struct edge{
    int to,cap,flow,next;
}e[M*2];
int head[N*2],ec=1;
void clear(){ memset(head,0,sizeof(head)); ec=1; }
void add(int a,int b,int cap){
    ec++; e[ec].to=b; e[ec].cap=cap; e[ec].flow=0;
    e[ec].next=head[a]; head[a]=ec;
}
void add2(int a,int b,int cap){
//  D(a); D(b); D(cap); E;
    add(a,b,cap); add(b,a,0);
}


bool vis[N*2]; int d[N*2];
bool bfs(){
    memset(vis,false,sizeof(vis));
    queue<int> q; q.push(S); vis[S]=true; d[S]=0;
    while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(!vis[v] && e[i].cap>e[i].flow){
                d[v]=d[u]+1; vis[v]=true;
                q.push(v);
                if(v==T) return true;   
            }
        }
    }
    return false;
}

int dfs(int u,int a){
    if(u==T || a==0) return a;
    int flow=0, f;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(d[v]==d[u]+1 && (f=dfs(v,min(a,e[i].cap-e[i].flow)))){
            flow+=f; a-=f;
            e[i].flow+=f; e[i^1].flow-=f;
            if(a==0) break;
        }
    }
    if(a) d[u]=-1;
    return flow;
}

int mxf(){
    int flow=0;
    while(bfs()){
        flow+=dfs(S,INF);
    }
    return flow;
}

void build(){
    clear();
    S=n+m+1; T=S+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            add2(i,j+n,19);
    for(int i=1;i<=n;i++) 
        add2(S,i,hang[i]-m);
    for(int i=1;i<=m;i++)
        add2(i+n,T,lie[i]-n);
}

int main(){
    freopen("a.in","r",stdin);
//  freopen("a.out","w",stdout);
    int T; cin>>T; int cas=0;
    while(T--){
        if(cas) puts("");
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&tp[i]);
            hang[i]=tp[i]-tp[i-1];
        }
        for(int i=1;i<=m;i++){
            scanf("%d",&tp[i]);
            lie[i]=tp[i]-tp[i-1];
        }
        build();
        mxf();
        printf("Matrix %d\n",++cas);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                int x=((i-1)*m+(j-1))*2+2;
                printf("%d ",e[x].flow+1);
            }
            puts("");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值