Uvalive 4865 Data Recovery 最大流

题意就是

给一个50 * 50的矩阵

然后给出每行每列元素的和

和一个初始矩阵

矩阵中有些是未知,有些是已知

然后我们求目标矩阵就是把能确定的元素的值求出来,实在不能确定的就置为-1

所有矩阵元素的值在0-100之间


看到范围很小。

第一反应是求一个最大流

先把已经给出的元素都从每行每列的和中减掉。

然后左边为行结点,右边为列结点

然后源点向行结点连边

列结点向汇点连边

行和列中如果对应的元素未知就连一下,流向上限是100

然后这样我们就得到了一个可行解

但是可能有多解怎么办

对于一个可能多解的元素

如果我们将这个元素的值固定住。

然后建立一个超级源点与该行结点连边。

该列结点与超级汇点连边。

流量都是1,

跑一遍看看有没有增广路。

如果有,显然这个位置的值是可以改变的,就是多解,然后我们把这个位置的元素值-1,因为我们刚才增广了,其他有元素的值增加了1,所以

为了保持流量的平衡,这个位置的元素要减1

但是这样还不行。

我们想想。

如果该位置的值现在是0怎么办。

他没法减掉1。

所以我们就要想想残余网络了。

既然他没法减掉1,就让他想办法+1,让别的元素-1去

那么我们可以用一个超级源点连接列结点。

行结点连接超级汇点

跑最大流,看有没有增广路。

也就是看他的残余网络能不能减掉1.即它自身+1

如果有增广路,跟之前一样,更新一下边


 

#include <iostream>

#include <cstdio>

#include <cstring>

#include <string>

#include <algorithm>

#include <cstdlib>

#include <cmath>

#define MAXN 106

#define MAXM 211111

#define INF 1111111111

using namespace std;

struct EDGE

{

    int v, next;

    int w;

}edge[MAXM];

int head[MAXN], e;

void init()

{

    memset(head, -1, sizeof(head));

    e = 0;

}

void add(int u, int v, int w)

{

    edge[e].v = v;

    edge[e].w = w;

    edge[e].next = head[u];

    head[u] = e++;

    edge[e].v = u;

    edge[e].w = 0;

    edge[e].next = head[v];

    head[v] = e++;

}

int n;

int h[MAXN];

int gap[MAXN];

int src, des;

int tt[111][111];

int dfs(int pos, int cost)

{

    if(pos == des) return cost;

    int j, minh = n - 1;

    int lv = cost, d;

    for(j = head[pos]; j != -1; j = edge[j].next)

    {

        int v = edge[j].v;

        int w = edge[j].w;

        if(w > 0)

        {

            if(h[v] + 1 == h[pos])

            {

                if(lv < edge[j].w) d = lv;

                else d = edge[j].w;

                d = dfs(v, d);

                edge[j].w -= d;

                edge[j ^ 1].w += d;

                lv -= d;

                if(h[src] >= n) return cost - lv;

                if(lv == 0) break;

            }

            if(h[v] < minh) minh = h[v];

        }

    }

    if(lv == cost)

    {

        --gap[h[pos]];

        if(gap[h[pos]] == 0) h[src] = n;

        h[pos] = minh + 1;

        ++gap[h[pos]];

    }

    return cost - lv;

}

int sap()

{

    int ret = 0;

    memset(gap, 0, sizeof(gap));

    memset(h, 0, sizeof(h));

    gap[0] = n;

    while(h[src] < n) ret += dfs(src, INF);

    return ret;

}

int nt, m;

int col[55], row[55];

int val[55][55], id[55][55];

int ans[55][55];

int vis[55][55];



int main()

{

    //freopen("C:/C.in", "r", stdin);

    //freopen("C:/C2.out", "w", stdout);

    while(scanf("%d%d", &nt, &m) != EOF)

    {

        if(!nt && !m) break;

        for(int i = 1; i <= nt; i++)

            for(int j = 1; j <= m; j++)

                scanf("%d", &val[i][j]);

        for(int i = 1; i <= nt; i++) scanf("%d", &row[i]);

        for(int i = 1; i <= m; i++) scanf("%d", &col[i]);

        memset(ans, -1, sizeof(ans));

        for(int i = 1; i <= nt; i++)

            for(int j = 1; j <= m; j++)

            {

                if(val[i][j] != -1)

                {

                    row[i] -= val[i][j];

                    col[j] -= val[i][j];

                    ans[i][j] = val[i][j];

                }

            }



        init();

        src = nt + m + 1;

        des = nt + m + 2;

        n = des;

        int S = nt + m + 3;

        int T = nt + m + 4;



        for(int i = 1; i <= nt; i++)

            for(int j = 1; j <= m; j++)

            {

                if(ans[i][j] == -1)

                {

                    id[i][j] = e;

                    add(i, j + nt, 100);

                }

            }

        for(int i = 1; i <= nt; i++)

        {

            add(src, i, row[i]);

        }

        for(int j = 1; j <= m; j++)

        {

            add(j + nt, des, col[j]);

        }

        sap();

        n = T;

        memset(vis, 0, sizeof(vis));

        for(int i = 1; i <= nt; i++)

            for(int j = 1; j <= m; j++)

                if(ans[i][j] != -1) vis[i][j] = 2;

        src = S;

        des = T;

        for(int i = 1; i <= nt; i++)

        {

            for(int j = 1; j <= m; j++)

            {

                if(vis[i][j] == 2) continue;

                int te = id[i][j];

                int tmp = edge[te ^ 1].w;

                edge[te].w = edge[te ^ 1].w = 0;

                int flag = 1;

                int le = e;

                add(src, i, 1);

                int me = e;

                add(j + nt, des, 1);

                if( tmp && sap()) flag = 0, tmp--;

                edge[le].w = edge[le ^ 1].w = 0;

                edge[me].w = edge[me ^ 1].w = 0;

                le = e;

                add(src, j + nt, 1);

                me = e;

                add(i, des, 1);

                if(flag  && 100 - tmp > 0&& sap()) flag = 0, tmp++;

                edge[le].w = edge[le ^ 1].w = 0;

                edge[me].w = edge[me ^ 1].w = 0;



                edge[te ^ 1].w = tmp;

                edge[te].w = 100 - tmp;

                vis[i][j] = flag;

            }



        }

        for(int i = 1; i <= nt; i++)

            for(int j = 1; j <= m; j++)

            {

                if(vis[i][j] == 2)

                {

                    if(ans[i][j] != -1) printf("%d", ans[i][j]);

                }

                else

                {

                    if(vis[i][j]) printf("%d", edge[id[i][j] ^ 1].w);

                    else printf("-1");

                }

                if(j < m) printf(" ");

                else printf("\n");

            }



    }

    return 0;

}


 

 

你可能感兴趣的:(Data)