• UVa 11082


    链接:

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2023

    题意:

    对于一个R行C列的正整数矩阵(1≤R,C≤20),设Ai为前i行所有元素之和,Bi为前i列所有元素之和。
    已知R,C和数组A和B,找一个满足条件的矩阵。矩阵中的元素必须是1~20之间的正整数。输入保证有解。

    分析:

    首先根据Ai和Bi计算出第i行的元素之和Ai'和第i列的元素之和Bi'。
    如果把矩阵里的每个数都减1,则每个Ai'会减少C,而每个Bi'会减少R。
    这样一来,每个元素的范围变成了0~19,它的好处很快就能看到。
    建立一个二分图,每行对应一个X结点,每列对应一个Y结点,然后增加源点s和汇点t。
    对于每个结点Xi,从s到Xi连一条弧,容量为Ai'-C;从Yi到t连一条弧,容量为Bi'-R。
    而对于每对结点(Xi,Yj),从Xi向Yj连一条弧,容量为19。
    接下来求s-t的最大流,如果所有s出发和到达t的边都满载,说明问题有解,
    结点Xi->Yj的流量就是格子(i,j)减1之后的值。

    代码:

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <queue>
      4 #include <vector>
      5 using namespace std;
      6 
      7 /// 结点下标从0开始,注意maxn
      8 struct Dinic {
      9     static const int maxn = 50 + 5;
     10     static const int INF = 0x3f3f3f3f;
     11     struct Edge {
     12         int from, to, cap, flow;
     13     };
     14 
     15     int n, m, s, t; // 结点数,边数(包括反向弧),源点编号和汇点编号
     16     vector<Edge> edges; // 边表。edges[e]和edges[e^1]互为反向弧
     17     vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
     18     bool vis[maxn]; // BFS使用
     19     int d[maxn]; // 从起点到i的距离
     20     int cur[maxn]; // 当前弧下标
     21 
     22     void init(int n) {
     23         this->n = n;
     24         edges.clear();
     25         for(int i = 0; i < n; i++) G[i].clear();
     26     }
     27     void AddEdge(int from, int to, int cap) {
     28         edges.push_back((Edge){from, to, cap, 0});
     29         edges.push_back((Edge){to, from, 0, 0});
     30         m = edges.size();
     31         G[from].push_back(m-2);
     32         G[to].push_back(m-1);
     33     }
     34     bool BFS() {
     35         memset(vis, 0, sizeof(vis));
     36         queue<int> Q;
     37         Q.push(s);
     38         vis[s] = 1;
     39         d[s] = 0;
     40         while(!Q.empty()) {
     41             int x = Q.front();  Q.pop();
     42             for(int i = 0; i < G[x].size(); i++) {
     43                 Edge& e = edges[G[x][i]];
     44                 if(!vis[e.to] && e.cap > e.flow) { // 只考虑残量网络中的弧
     45                     vis[e.to] = 1;
     46                     d[e.to] = d[x] + 1;
     47                     Q.push(e.to);
     48                 }
     49             }
     50         }
     51         return vis[t];
     52     }
     53     int DFS(int x, int a) {
     54         if(x == t || a == 0) return a;
     55         int flow = 0, f;
     56         for(int& i = cur[x]; i < G[x].size(); i++) { // 从上次考虑的弧
     57             Edge& e = edges[G[x][i]];
     58             if(d[x]+1 == d[e.to] && (f=DFS(e.to, min(a, e.cap-e.flow))) > 0) {
     59                 e.flow += f;
     60                 edges[G[x][i]^1].flow -= f;
     61                 flow += f;
     62                 a -= f;
     63                 if(a == 0) break;
     64             }
     65         }
     66         return flow;
     67     }
     68     int Maxflow(int s, int t) {
     69         this->s = s;  this->t = t;
     70         int flow = 0;
     71         while(BFS()) {
     72             memset(cur, 0, sizeof(cur));
     73             flow += DFS(s, INF);
     74         }
     75         return flow;
     76     }
     77     vector<int> Mincut() { // 在Maxflow之后调用
     78         vector<int> ans;
     79         for(int i = 0; i < edges.size(); i++) {
     80             Edge& e = edges[i];
     81             if(vis[e.from] && !vis[e.to] && e.cap > 0) ans.push_back(i);
     82         }
     83         return ans;
     84     }
     85 };
     86 
     87 const int UP = 20 + 5;
     88 int id[UP][UP];
     89 Dinic dc;
     90 
     91 int main() {
     92     int T, R, C;
     93     scanf("%d", &T);
     94     for(int cases = 1; cases <= T; cases++) {
     95         scanf("%d%d", &R, &C);
     96         dc.init(R+C+2);
     97         int start = R+C, finish = R+C+1, last = 0;
     98         for(int v, i = 0; i < R; i++) {
     99             scanf("%d", &v);
    100             dc.AddEdge(start, i, v - last - C);
    101             last = v;
    102         }
    103         last = 0;
    104         for(int v, i = 0; i < C; i++) {
    105             scanf("%d", &v);
    106             dc.AddEdge(R+i, finish, v - last - R);
    107             last = v;
    108         }
    109         for(int r = 0; r < R; r++) {
    110             for(int c = 0; c < C; c++) {
    111                 dc.AddEdge(r, R+c, 19);
    112                 id[r][c] = dc.edges.size() - 2;
    113             }
    114         }
    115 
    116         dc.Maxflow(start, finish);
    117         printf("Matrix %d
    ", cases);
    118         for(int r = 0; r < R; r++) {
    119             for(int c = 0; c < C; c++) {
    120                 printf("%d ", dc.edges[id[r][c]].flow + 1);
    121             }
    122             printf("
    ");
    123         }
    124         printf("
    ");
    125     }
    126     return 0;
    127 }
  • 相关阅读:
    如何测试一个网页登陆界面
    吞吐量(TPS)、QPS、并发数、响应时间(RT)概念
    postman接口案例
    接口定义
    socket网络编程
    分页读取文件内容
    hashlib,configparser,logging,模块
    python面向对象编程
    常用模块
    迭代器和生成器
  • 原文地址:https://www.cnblogs.com/hkxy125/p/9538445.html
Copyright © 2020-2023  润新知