例题11-8 矩阵解压 UVa11082

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];//记录v
	int 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);//同理,注意为了区分行和列的下标,要多加一个R
	for (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;
}
时间: 2024-08-10 16:58:43

例题11-8 矩阵解压 UVa11082的相关文章

UVA 11082 Matrix Decompressing 矩阵解压(最大流,经典)

题意:知道矩阵的前i行之和,和前j列之和(任意i和j都可以).求这个矩阵.每个格子中的元素必须在1~20之间.矩阵大小上限20*20. 思路: 这么也想不到用网络流解决,这个模型很不错.假设这个矩阵的每一行是水管,每一列是水管,每行有出水口流到每一列,这样想比较好理解.然后每行的流量和每列的流量知道,就可以建图了. 建图过程,每行对应一个点,每列对应1个点,每行都可以流到每列,所以他们之间有边.我们得假设他们是如何流向的,不如设从行流向列,那么添加源点,流向每行:添加汇点,被每列汇流.容量怎么设

【UVA11082】Matrix Decompressing(有上下界的网络流)

题意:给出一个矩阵前i列所有元素的和,和前j行所有元素的和,求这个矩阵解压以后的原型.(答案不唯一) n,m<=20,1<=a[i,j]<=20 思路:这道题把边上的流量作为原先矩阵中的点 把每一行,每一列都看成一个点 S-->i行 a[i]-m i行-->j列 19 j列-->T b[i]-n 跑最大流,边(i,j+n)上的流量就是a[i,j]的值 为什么容量是a[i]-m,19,b[i]-n? 因为点权(边权)不能为0,所以要先把所有值+1,上限就-1,输出的时候+

VB6解压GZIP和C#解压GZIP

VB进行GZIP解压的,DLL是系统的,如果没有点击这里下载 1 Option Explicit 2 'GZIP API 3 '-------------------------------------------------- 4 Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length A

ICSharpCode.SharpZipLi 压缩、解压文件 附源码

http://www.icsharpcode.net/opensource/sharpziplib/ 有SharpZiplib的最新版本,本文使用的版本为0.86.0.518,支持Zip, GZip, BZip2 和Tar格式 我们需要dll 在官网上也有,也可以从百度网盘下载 好了,深入的大家还要多多研究,今天我们简单介绍一下 简单的 单文件.文件夹的压缩和解压 先给大家看一下效果: 一.引入ICSharpCode.SharpZipLib 我们新建个帮助类 ZipHelper.cs  然后 添

ICSharpCode.SharpZipLib 压缩、解压文件 附源码

http://www.icsharpcode.net/opensource/sharpziplib/ 有SharpZiplib的最新版本,本文使用的版本为0.86.0.518,支持Zip, GZip, BZip2 和Tar格式 我们需要dll 在官网上也有,也可以从百度网盘下载 好了,深入的大家还要多多研究,今天我们简单介绍一下 简单的 单文件.文件夹的压缩和解压 先给大家看一下效果: 一.引入ICSharpCode.SharpZipLib 我们新建个帮助类 ZipHelper.cs  然后 添

Oracle database 11.2.0.3.0 升级至 11.2.0.3.14

下载PSU p20299017_112030_Linux-x86-64(DATABASE PATCH SET UPDATE 11.2.0.3.14 (INCLUDES CPUAPR2015)).zip 及Opatch p6880880_112000_Linux-x86-64(OPatch patch of version 11.2.0.3.10 for Oracle software releases 11..zip 下载地址 http://yunpan.cn/cHACmBerMb526 访问密

libcurl-7.54.1附加zlib1.2.11的编译

手上有个小程序需要通过HTTP协议通信,选择了出名的libcurl作为支持库.由于网上的教程多是命令行编译,本人记性不好,比较讨厌记住一堆命令,因此折腾了一天通过VS对libcurl和zlib进行了编译.下面就将编译过程记录下作为备忘. 一.环境及库版本介绍 win10 64位.VS_professional_2013_with_update_5.curl-7.54.1.zlib-1.2.11 二.目的 生成libcurl静态库,并支持在xp下使用 三.开始 1.编译zlib 从http://w

CentOS7搭建FastDFS V5.11分布式文件系统-第二篇

1.CentOS7 FastDFS搭建 前面已下载好了要用到的工具集,下面就可以开始安装了: 如果安装过程中出现问题,可以下载我提供的,当前测试可以通过的工具包: 点这里点这里 1.1 安装libfastcommon 安装成功后解压libfastcommon-master.zip unzip libfastcommon-master.zip [[email protected] libfastcommon-1.0.36]# ll drwxr-xr-x. 2 root root 4096 4月 5

CentOS7搭建FastDFS V5.11分布式文件系统(二)

1.CentOS7 FastDFS搭建 前面已下载好了要用到的工具集,下面就可以开始安装了: 如果安装过程中出现问题,可以下载我提供的,当前测试可以通过的工具包: 点这里点这里 1.1 安装libfastcommon 安装成功后解压libfastcommon-master.zip unzip libfastcommon-master.zip [[email protected] libfastcommon-1.0.36]# ll drwxr-xr-x. 2 root root 4096 4月 5