题目描述

给两个\(n×m\)的矩阵A和B,你可以进行若干次操作。每次操作你可以使A或B的某一行或者某一列的所有元素增加1。
问至少要多少次操作,才能使A和B相等。

输入格式

从文件a.in中读入数据。
第一行一个正整数T,表示数据组数。
每组数据的第一行两个正整数n,m。
接下来n行,每行m个非负整数\(A_{i,j}\),表示矩阵A。
接下来n行,每行m个非负整数\(B_{i,j}\),表示矩阵B。

输出格式

输出到文件a.out中。
对于每组数据,输出一行一个整数表示答案。如果无论怎么操作都不能使得A和B相等,输出−1。

解析

用到数学代换比较多,首先B矩阵加相当于A矩阵减,所以我们只关心A矩阵的变化。
设A第i行需要增加\(r_i\),第i列需要增加\(c_i\),我们的目标是求最小的\(\sum|r_i| + \sum|c_i|\)
\(r_1 = x\),通过第一行的信息可以得到\(c_i = B_{1, i} – A_{1, i} – x\),通过第一列得到\(r_i = B_{i,1} – A_{i,1} – B_{1,1}+A_{1,1} + x\)
有一个显然的性质\(A_{i,j} + r_i + c_j = B_{i,j}\),通过此判断无解情况。
最后要求形如\(\sum_{i = 1} ^ {n + m} |x – a _ i|\)的形式(注意只是形如),那么通过数学可以知道x取a的中位数的答案最小。

代码

#include <bits/stdc++.h>
#define ll long long
#define eb emplace_back
using namespace std;
const int N = 1e5 + 10;
int T, n, m;
ll a[N], b[N];
int id(int x, int y) {return (x - 1) * m + y;}
void solve() {
	ll ans = 0;
	vector<ll> vec;
	cin >> n >> m;
	for (int i = 1; i <= n * m; i ++) cin >> a[i];
	for (int i = 1; i <= n * m; i ++) {
		cin >> b[i]; a[i] = b[i] - a[i];
	}
	for (int i = 1; i <= n; i ++)
		for (int j = 1; j <= m; j ++)
			if (a[id(i, j)] != a[id(1, j)] - a[id(1, 1)] + a[id(i, 1)])
				//return puts("-1"), void();
				{puts("-1"); return ;}
	for (int i = 1; i <= n; i ++) vec.eb(a[1] - a[(i - 1) * m + 1]);
	for (int i = 1; i <= m; i ++) vec.eb(a[i]);
	sort(vec.begin(), vec.end());
	ll x = vec[(n + m) / 2];//取中位数
	for (auto p : vec) ans += abs(x - p);
	printf("%lld\n", ans); 
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin >> T;
	while (T --) solve();
	return 0;
}

image
(额……)

原文地址:http://www.cnblogs.com/YHxo/p/16800260.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性