Uvalive 4865 Data Recovery 最大流

来源:互联网 发布:淘宝店图片轮播制作 编辑:程序博客网 时间:2024/04/29 17:15

题意就是

给一个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 1111111111using 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;}


原创粉丝点击