zoukankan      html  css  js  c++  java
  • 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("
    ");
                }
    
        }
        return 0;
    }
    


  • 相关阅读:
    PAT Advanced 1044 Shopping in Mars (25) [⼆分查找]
    PAT Advanced 1029 Median (25) [two pointers]
    PAT Advanced 1010 Radix(25) [⼆分法]
    PAT Basic 1070 结绳(25) [排序,贪⼼]
    PAT Basic 1023 组个最⼩数 (20) [贪⼼算法]
    PAT Basic 1020 ⽉饼 (25) [贪⼼算法]
    PAT Advanced 1070 Mooncake (25) [贪⼼算法]
    PAT Advanced 1067 Sort with Swap(0,*) (25) [贪⼼算法]
    PAT Advanced 1038 Recover the Smallest Number (30) [贪⼼算法]
    PAT Advanced 1037 Magic Coupon (25) [贪⼼算法]
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3370829.html
Copyright © 2011-2022 走看看