zoukankan      html  css  js  c++  java
  • uva11082 Matrix Decompressing

    证明:

    对于每一个X节点,都是只有一个入流,多个出流(分别流向每一个Y节点),显然多个出流的和正好等于入流;同理,对于每一个Y节点,有多个入流(分别来自每一个X节点),只有一个出流,显然多个入流的和等于出流。第一类弧,以每一行所有元素之和为容量;第三类弧,以每一列所有元素之和为容量;第二类弧,最终流量为矩阵中的每一个元素。也就是说,第一类弧分成多个分支,每一个第一类弧都分出一个分支汇到同一个第三类弧。再考虑矩阵:把每一行的和分成多个元素,每一行的和都会分出一个元素排列在同一列,组成这一列的和。只要求出每一个第二类弧的流量,就是求出了矩阵中的每一个元素。

    注意建图技巧

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<algorithm>
    using namespace std;
    
    const int maxn = 50 + 5;
    const int INF = 1000000000;
    
    struct Edge {
      int from, to, cap, flow;
      Edge(int u, int v, int c, int f):from(u),to(v),cap(c),flow(f) {}
    };
    
    struct EdmondsKarp {
      int n, m;
      vector<Edge> edges;    // 边数的两倍
      vector<int> G[maxn];   // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
      int a[maxn];           // 当起点到i的可改进量
      int p[maxn];           // 最短路树上p的入弧编号
    
      void init(int n) {
        for(int i = 0; i < n; i++) G[i].clear();
        edges.clear();
      }
    
      void AddEdge(int from, int to, int cap) {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
      }
    
      int Maxflow(int s, int t) {
        int flow = 0;
        for(;;) {
          memset(a, 0, sizeof(a));
          queue<int> Q;
          Q.push(s);
          a[s] = INF;
          while(!Q.empty()) {
            int x = Q.front(); Q.pop();
            for(int i = 0; i < G[x].size(); i++) {
              Edge& e = edges[G[x][i]];
              if(!a[e.to] && e.cap > e.flow) {
                p[e.to] = G[x][i];
                a[e.to] = min(a[x], e.cap-e.flow);
                Q.push(e.to);
              }
            }
            if(a[t]) break;
          }
          if(!a[t]) break;
          for(int u = t; u != s; u = edges[p[u]].from) {
            edges[p[u]].flow += a[t];
            edges[p[u]^1].flow -= a[t];
          }
          flow += a[t];
        }
        return flow;
      }
    };
    
    EdmondsKarp g;
    int no[maxn][maxn];
    
    int main() {
      int T, R, C, v, kase = 0;
      scanf("%d", &T);
      for(int kase = 1; kase <= T; kase++) {
        scanf("%d%d", &R, &C);
        g.init(R+C+2);                     //初始化  注意R+C+2
        int last = 0;
        for(int i = 1; i <= R; i++) {
          scanf("%d", &v);
          g.AddEdge(0, i, v - last - C); // row sum is v - last //S到行Ai
          last = v;
        }
        last = 0;
        for(int i = 1; i <= C; i++) {
          scanf("%d", &v);
          g.AddEdge(R+i, R+C+1, v - last - R); // col sum is v - last  //用R+j
          last = v;
        }
    
        for(int i = 1; i <= R; i++)
          for(int j = 1; j <= C; j++) {
            g.AddEdge(i, R+j, 19);
            no[i][j] = g.edges.size() - 2; // no[i][j] is the index of arc for cell(i,j)
          }                                //-2是因为加了反向边
        g.Maxflow(0, R+C+1);
    
        printf("Matrix %d
    ", kase);
        for(int i = 1; i <= R; i++) {
          for(int j = 1; j <= C; j++)
            printf("%d ", g.edges[no[i][j]].flow + 1); // we subtracted 1 from every cell
          printf("
    ");
        }
        printf("
    ");
      }
      return 0;
    }
  • 相关阅读:
    LeetCode-求最长回文子序列
    C++四种类型转换总结
    kmp算法分析和C++实现
    把二叉树打印成多行
    考研数据结构笔记—堆排序
    天勤考研数据结构笔记—栈的C语言实现
    合并两个排序的链表递归和非递归C++实现
    二叉树的线索化
    单链表的基本操作实现
    OpenFaceswap 入门教程(3): 软件参数篇!
  • 原文地址:https://www.cnblogs.com/lqerio/p/9860927.html
Copyright © 2011-2022 走看看