UVa 11082 - Matrix Decompressing(最大流)

博客围绕一个R行C列正整数矩阵问题展开。已知R、C及数组A和B,需找满足条件的矩阵。先计算每行和每列元素之和,将矩阵元素范围转化为0 - 19,建立二分图,通过添加源点和汇点连弧,求s - t最大流判断问题是否有解,流量对应格子值减1后的值。

链接:

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\n", 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("\n");
123         }
124         printf("\n");
125     }
126     return 0;
127 }

 

转载于:https://www.cnblogs.com/hkxy125/p/9538445.html

内容概要:本文系统介绍了算术优化算法(AOA)的基本原理、核心思想及Python实现方法,并通过图像分割的实际案例展示了其应用价值。AOA是一种基于种群的元启发式算法,其核心思想来源于四则运算,利用乘除运算进行全局勘探,加减运算进行局部开发,通过数学优化器加速函数(MOA)和数学优化概率(MOP)动态控制搜索过程,在全局探索与局部开发之间实现平衡。文章详细解析了算法的初始化、勘探与开发阶段的更新策略,并提供了完整的Python代码实现,结合Rastrigin函数进行测试验证。进一步地,以Flask框架搭建前后端分离系统,将AOA应用于图像分割任务,展示了其在实际工程中的可行性与高效性。最后,通过收敛速度、寻优精度等指标评估算法性能,并提出自适应参数调整、模型优化和并行计算等改进策略。; 适合人群:具备一定Python编程基础和优化算法基础知识的高校学生、科研人员及工程技术人员,尤其适合从事人工智能、图像处理、智能优化等领域的从业者;; 使用场景及目标:①理解元启发式算法的设计思想与实现机制;②掌握AOA在函数优化、图像分割等实际问题中的建模与求解方法;③学习如何将优化算法集成到Web系统中实现工程化应用;④为算法性能评估与改进提供实践参考; 阅读建议:建议读者结合代码逐行调试,深入理解算法流程中MOA与MOP的作用机制,尝试在不同测试函数上运行算法以观察性能差异,并可进一步扩展图像分割模块,引入更复杂的预处理或后处理技术以提升分割效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值