Cordforces 1774D题解

题目链接: https://codeforces.com/problemset/problem/1774/D
Description:
给定n个长为m的二进制串,每次可以选出任意两个,然后交换这两个二进制串同一列的数。求最少的操作次数,使得每一行含有的1的数量相等。
input:
第一行是测试案例的数目。
每个测试案例的第一行包含两个字符n, m(2 ≤ n ≤ 10^5, 2 ≤ m ≤ 10^5)。
接下来n行每行包含m个仅为0或1的数字,是二进制串的具体内容。
output:
如果没有办法做到每行含有的1数目相等,输出-1,否则在第一行输出最少的操作次数k,
然后接下来k行,每行输出三个字符,其中前两个是选中的行,第三个是选中的列

Sample input:

3
3 4
1 1 1 0
0 0 1 0
1 0 0 1
4 3
1 0 0
0 1 1
0 0 1
0 0 0
2 2
0 0
0 1

Sample output:

1
2 1 1
1
4 2 2
-1

先统计每行1的个数, 并且计算出来每行应该有多少个。然后按列遍历,对于第j列, 如果第i行1的个数多于平均值并且g[i][j]是1的话就记录下来,如果第i行1的个数小于平均值并且g[i][j]是0的话也记录下来。
Code:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
#define int LL

struct Node {
	int x, y, z;
};

void solve(void) {
	int n, m; cin >> n >> m;
	int cnt = 0; int f[n + 1];
	memset(f, 0, sizeof f);
	vector<int> g[n + 1];
	for(int i = 1; i <= n; i ++) {
		g[i].resize(m + 1);
		for(int j = 1; j <= m; j ++) {
			cin >> g[i][j];
			if(g[i][j]) {
				cnt ++;
				f[i] ++;
			}
		}
	}
	if(cnt % n) {
		cout << "-1\n";
		return;
	}
	cnt /= n;
	vector<Node> ans;
	for(int i = 1; i <= m; i ++) {
		queue<int> que1, que2;
		for(int j = 1; j <= n; j ++) {
			if(f[j] > cnt && g[j][i]) que1.push(j);
			if(f[j] < cnt && !g[j][i]) que2.push(j);
		}
		while(que1.size() && que2.size()) {
			int x = que1.front();
			int y = que2.front();
			que1.pop();
			que2.pop();
			f[x] --; f[y] ++;
			ans.push_back({x, y, i});
		}
	}
	cout << ans.size() << '\n';
	for(int i = 0; i < ans.size(); i ++) {
		cout << ans[i].x << ' ' << ans[i].y << ' ' << ans[i].z << '\n';
	}
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t; cin >> t;
	while(t --) solve();
}
posted @ 2022-12-28 16:47  zuotihenkuai  阅读(28)  评论(0编辑  收藏  举报