例题11-8 矩阵解压 UVa11082
来源:互联网 发布:像初页一样的软件 编辑:程序博客网 时间:2024/04/28 13:30
1.题目描述:点击打开链接
2.解题思路:本题的突破口在于建模,其实关于最大流的问题大多数难点都在建模上。本题只告诉了我们前i行,前i列的和值,让求解整个矩阵。事先可以算出第i行的和值和第i列的和值。然后该怎么办呢?由于每个元素都是1~20之间的,因此如果把所有元素都减去1,那么正好是0·19之间,因此联想到每条边的容量是19。此时行的和值要减去C,列的和值减去R。根据网络流的性质:流入结点的流量等于流出结点的流量。因此可以从此着手构造模型:假设每行对应一个X结点,每列对应一个Y结点,然后增加源点s,汇点t。对于每个结点Xi,从s到Xi连接一条弧,容量是A[i]-C(此时所有的A[i],B[i]均值第i行,第i列的和值);从Yi到t连接一条弧,容量是B[i]-R。对于每个结点(Xi,Yj),从Xi到Yj连接一条弧,容量是19。这样的一个网络便满足了之前题目中的所有性质。接下来只用求出s-t的最大流,那么如果s出发和到达t都满载,说明问题有解。结点Xi->Yj的流量就是格子(i,j)减1的值。本题的一个新知识点是int的最大上界表示:~0U>>1,另一个知识点是采用了链表结构的Dinic算法的写法。
3.代码:
#define _CRT_SECURE_NO_WARNINGS #include<iostream>#include<algorithm>#include<string>#include<sstream>#include<set>#include<vector>#include<stack>#include<map>#include<queue>#include<deque>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<functional>using namespace std;const int INF = ~0U >> 1;//即int的最大值struct Dinic{static const int N = 510, M = 100010;int head[N];//链表头部,存储以u开始的边序号int en[M];//记录vint Next[M];//记录下一条边的序号int cap[M];//记录容量int tot;//边数void clear(){memset(head, 0, sizeof(head));tot = 1;}void add(int u, int v, int w){en[++tot] = v;Next[tot] = head[u];head[u] = tot;cap[tot] = w;}void Add(int u, int v, int w){ add(u, v, w); add(v, u, 0); }int d[N], cur[N];int n, s, t;bool bfs(){queue<int>q;memset(d, -1, sizeof(d));d[s] = 0;q.push(s);while (!q.empty()){int x = q.front(); q.pop();for (int k = head[x],v; k; k = Next[k])if (cap[k] && d[v = en[k]]==-1){d[v] = d[x] + 1;q.push(v);}}return d[t] != -1;}int dfs(int x, int y){if (x == t || !y)return y;int z = y;for (int&k = cur[x],v; k; k = Next[k])if (cap[k] && d[v = en[k]] == d[x] + 1){int w = dfs(v, min(cap[k], z));cap[k] -= w;//流量增大意味着净容量减少cap[k ^ 1] += w;//反向边容量表示了正向边的流量z -= w;if (!z)break;}if (z == y)d[x] = -1;return y - z;}int Maxflow(int s, int t){this->s = s, this->t = t;int flow = 0;while (bfs()){for (int i = 1; i <= n; i++)cur[i] = head[i];flow += dfs(s, INF);}return flow;}}g;int r[25], c[25], R, C, rnd;void solve(){scanf("%d%d", &R, &C);for (int i = 1; i <= R; i++)scanf("%d", r + i);for (int i = 1; i <= C; i++)scanf("%d", c + i);int s = R + C + 1, t = R + C + 2;g.n = R + C + 2;for (int i = 1; i <= R; i++)g.Add(s, i, r[i] - r[i - 1] - C);//r[i]-r[i-1]就是第i行的和值for (int i = 1; i <= C; i++)g.Add(R + i, t, c[i] - c[i - 1] - R);//同理,注意为了区分行和列的下标,要多加一个Rfor (int i = 1; i <= R;i++)for (int j = 1; j <= C; j++)g.Add(i, R + j, 19);g.Maxflow(s, t);printf("Matrix %d\n", ++rnd);for (int i = 1; i <= R; i++){vector<int>ans;for (int k = g.head[i]; k; k = g.Next[k])if (g.en[k] != g.s)ans.push_back(g.cap[k ^ 1] + 1);//k的反向边的容量表示k的流量for (int j = ans.size() - 1; j >= 0; j--)//由于新的边位于链表首位,因此要逆序输出printf("%d%c", ans[j], j ? ' ' : '\n');}}int main(){//freopen("t.txt", "r", stdin);int T;cin >> T;while (T--){g.clear();solve();if (T)puts("");}return 0;}
0 0
- 例题11-8 矩阵解压 UVa11082
- 矩阵解压(UVa11082)
- UVA11082 矩阵展开,最大流
- uva11082
- UVA11082
- UVa11082
- uva11082 知道矩阵每行每列数字之和 求矩阵每一个元素 最大流
- 例题7:偶数矩阵
- 矩阵DP例题
- [刷题]UVA11082
- 例题1.7 偶数矩阵 UVa11464
- 矩阵快速幂 例题+模板
- 例题:求矩阵代数余子式
- C语言蛇形矩阵例题
- 矩阵求导计算法则 例题
- [最大流]UVa11082
- 矩阵模版(例题3070、3744)
- 入门经典 例题9-2 嵌套矩阵
- HTML frame,iframe,frameset之间的关系与区别
- 利用systemd按需激Docker容器
- 下面对如何在Eclipse中添加java文档和类库源码进行总结。
- 黑马程序员-----享元设计模式
- 处女代码(实现弹出对话框)
- 例题11-8 矩阵解压 UVa11082
- 重复造轮子-更方便的Apk反编译
- LINUX下GCC的动态与静态编译
- Playmaker 如何让设计人员也能用
- centos7下安装tomcat7总结
- 学习Spring必学的Java基础知识(1)----反射
- Request和response总结
- How the Computer Works (based on X86/Linux)
- [线段树] HDU 1394 - Minimum Inversion Number