• 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
    ", 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("
    ");
    115         }
    116         printf("
    ");
    117     }
    118 
    119     return 0;
    120 }
    代码君
  • 相关阅读:
    jenkins+newman+postman实现api自动化
    数据库的关闭方法
    获取2台linux机器的时间差
    性能测试与其分析
    todo:云数据库的元信息
    todo:trove命令使用
    syslog协议及rsyslog服务全解析
    C++Primer学习日记
    excel-填充
    excel-删除
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4280727.html
Copyright © 2020-2023  润新知