UVa 11082 (网络流建模) Matrix Decompressing

网络流不难写,难的建一个能解决问题的模型。。

即使我知道这是网络流专题的题目,也绝不会能想出这种解法,=_=||

题意:

给出一个矩阵的 前i行和 以及 前i列和,然后找到一个满足要求的矩阵,而且每个元素在1~20之间。

分析:

先求出每行的元素和A'i    每列的元素和B'i

紫书上说建一个二分图,每行是一个X节点,每列代表一个Y节点。

因为流量最小是0,而题中说元素大小在1~20之间,所以我们先将每个元素都减一。

这样每行的元素和就变成了A'i-C,每列之和变为B'i-R

XY之间每条边的容量为19

源点到X中每个点的容量为A'i-C,Y中的每个点到汇点的容量为B'i-R。当所有从源点出发和在汇点结束的边满载时有解。

 

“为什么这样做是对的呢?请读者思考。”

好吧,那我就思考。Xi->Yj这条边就对应矩阵中第i行第j列元素的值,而且所有从X出发的边,汇聚到Yj的总流量就是第j列的和。

反过来,从Xi出发的总流量就是第i行的和,分流到各个Y中。

  1 #include <bits/stdc++.h>

  2 

  3 using namespace std;

  4 

  5 const int maxn = 50 + 5;

  6 const int INF = 1000000000;

  7 

  8 struct Edge

  9 {

 10     int from, to, cap, flow;

 11     Edge(int u=0, int v=0, int c=0, int f=0): from(u), to(v), cap(c), flow(f) {}

 12 };

 13 

 14 struct EdmondsKarp

 15 {

 16     int n, m;

 17     vector<Edge> edges;

 18     vector<int> G[maxn];

 19     int a[maxn];

 20     int p[maxn];

 21 

 22     void Init(int n)

 23     {

 24         for(int i = 0; i < n; ++i) G[i].clear();

 25         edges.clear();

 26     }

 27 

 28     void AddEdge(int from, int to, int cap)

 29     {

 30         edges.push_back(Edge(from, to, cap, 0));

 31         edges.push_back(Edge(to, from, 0, 0));

 32         m = edges.size();

 33         G[from].push_back(m-2);

 34         G[to].push_back(m-1);

 35     }

 36 

 37     int MaxFlow(int s, int t)

 38     {

 39         int flow = 0;

 40         for(;;)

 41         {

 42             memset(a, 0, sizeof(a));

 43             queue<int> Q;

 44             Q.push(s);

 45             a[s] = INF;

 46             while(!Q.empty())

 47             {

 48                 int x = Q.front(); Q.pop();

 49                 for(int i = 0; i < G[x].size(); ++i)

 50                 {

 51                     Edge& e = edges[G[x][i]];

 52                     if(!a[e.to] && e.cap > e.flow)

 53                     {

 54                         a[e.to] = min(a[x], e.cap - e.flow);

 55                         p[e.to] = G[x][i];

 56                         Q.push(e.to);

 57                     }

 58                 }

 59                 if(a[t]) break;

 60             }

 61             if(!a[t]) break;

 62             for(int u = t; u != s; u = edges[p[u]].from)

 63             {

 64                 edges[p[u]].flow += a[t];

 65                 edges[p[u]^1].flow -= a[t];

 66             }

 67             flow += a[t];

 68         }

 69         return flow;

 70     }

 71 };

 72 

 73 EdmondsKarp g;

 74 int ind[maxn][maxn];//ind[i][j]记录第i行第j列对应的边的编号

 75 

 76 int main()

 77 {

 78     //freopen("in.txt", "r", stdin);

 79 

 80     int T, R, C;

 81     scanf("%d", &T);

 82     for(int kase = 1; kase <= T; ++kase)

 83     {

 84         scanf("%d%d", &R, &C);

 85         g.Init(R+C+2);

 86         int cur, last = 0;

 87         for(int i = 1; i <= R; ++i)

 88         {//第i行的节点标号为i,源点标号为0

 89             scanf("%d", &cur);

 90             g.AddEdge(0, i, cur - last - C);

 91             last = cur;

 92         }

 93         last = 0;

 94         for(int i = 1; i <= C; ++i)

 95         {//第i列的标号为R+i,汇点标号为R+C+1

 96             scanf("%d", &cur);

 97             g.AddEdge(R+i, R+C+1, cur - last - R);

 98             last = cur;

 99         }

100         for(int i = 1; i <= R; ++i)

101             for(int j = 1; j <= C; ++j)

102             {

103                 g.AddEdge(i, j+R, 19);

104                 ind[i][j] = g.edges.size() - 2;//因为AddEdge中还有一条反向边,所以是-2

105             }

106         g.MaxFlow(0, R+C+1);

107 

108         printf("Matrix %d\n", kase);

109         for(int i = 1; i <= R; ++i)

110         {

111             printf("%d", g.edges[ind[i][1]].flow + 1);

112             for(int j = 2; j <= C; ++j)

113                 printf(" %d", g.edges[ind[i][j]].flow + 1);

114             printf("\n");

115         }

116         printf("\n");

117     }

118 

119     return 0;

120 }
代码君

 

你可能感兴趣的:(compress)