CF1713E. Cross Swapping

Difficulty:2400

题意

n×n(1n1000) 的矩阵 a ,每次操作可以选择一个 k(1kn) ,交换每个 aikaki 。可以进行若干次操作,求能够得到的字典序最小的矩阵(即按一行一行的顺序对元素作比较)。

思路

考虑任意一个操作做两次其效果会抵消,如果要交换 aijaji ,则必然是 ij 中一个进行操作,另外一个不进行。如果不要交换,则要么两者都进行操作,要么都不进行。f发现所有的操作可以构成一个二分图,于是我们可以按顺序贪心地考虑,对于每个 aij(i>j) 来决定是否交换,如果 aij>aji ,那么则需要交换,否则不需要,相等的时候不用考虑,交不交换都不影响。外如果操作间会发生冲突,则舍去准备加入的操作,可以用扩展域并查集来维护每个操作所属的集合,如果需要交换,则在 i,j 间连边,表示不会同时进行,否则新建节点 v ,连边 (i,v)(j,v) 表示需要同时进行,最后进行二分图染色,任选其中一个部分执行对应操作计科,复杂度 O(n2)

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<LL, LL>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mul(x,y) (1ll*(x)*(y)%mod)
#define mk make_pair
//#define int LL
//#define double LD
#define lc tr[x].ch[0]
#define rc tr[x].ch[1]
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-10;
const double pi = acos(-1);
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 1010;

int T, N, A[maxn][maxn], par[maxn * 2], rk[maxn * 2], col[maxn * maxn], tot;
vector<int>G[maxn * maxn];

void add_edge(int from, int to)
{
	G[from].push_back(to);
	G[to].push_back(from);
}

void init()
{
	for (int i = 1; i <= N * 2; i++)
		par[i] = i, rk[i] = 0;
}

int find(int x)
{
	if (par[x] == x)
		return x;
	return par[x] = find(par[x]);
}

void unite(int x, int y)
{
	x = find(x), y = find(y);
	if (x == y)
		return;
	if (rk[x] < rk[y])
		par[x] = y;
	else
	{
		par[y] = x;
		if (rk[x] == rk[y])
			rk[x]++;
	}
}

bool same(int x, int y)
{
	return find(x) == find(y);
}

void dfs(int v, int p, int x)
{
	col[v] = x;
	for (auto& to : G[v])
	{
		if (to == p || col[to] != -1)
			continue;
		dfs(to, v, x ^ 1);
	}
}

void solve()
{
	init(), tot = N;
	for (int i = 1; i <= N; i++)
	{
		for (int j = i + 1; j <= N; j++)
		{
			if (A[i][j] == A[j][i])
				continue;
			if (A[i][j] > A[j][i])
			{
				if (!same(i, j) && !same(i + N, j + N))
					unite(i, j + N), unite(j, i + N), add_edge(i, j);
			}
			else
			{
				if (!same(i, j + N) && !same(i + N, j))
					unite(i, j), unite(i + N, j + N), add_edge(i, ++tot), add_edge(tot, j);
			}
		}
	}
	for (int i = 1; i <= N; i++)
	{
		if (col[i] == -1)
			dfs(i, 0, 1);
	}
		for (int k = 1; k <= N; k++)
		{
			if (col[k]==1)
			{
				for (int i = 1; i <= N; i++)
					swap(A[k][i], A[i][k]);
			}
		}
	for (int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= N; j++)
			cout << A[i][j] << ' ';
		cout << endl;
	}
	for (int i = 1; i <= tot; i++)
		G[i].clear(), col[i] = -1;
}

int main()
{
	IOS;
	mst(col, -1);
	cin >> T;
	while (T--)
	{
		cin >> N;
		for (int i = 1; i <= N; i++)
		{
			for (int j = 1; j <= N; j++)
				cin >> A[i][j];
		}
		solve();

	}

	return 0;
}
posted @   Prgl  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示