题解 [ABC332D] Swapping Puzzle

【洛谷博客】

这题可能是 ABC 的 D 题里面难度的中等偏上,感觉确实和其他的 D 题相比有点难以实现。

题意

给两个 \(H \times W\) 的矩阵 \(A\)\(B\)

你可以对 \(A\) 矩阵交换相邻两行或相邻两列若干次。

输出 \(A\) 变换为 \(B\) 的最小操作次数,如果不能则输出 -1

分析

\(2 \le H,W \le 5\),提醒着我们这个算法可能有一个指数级或者阶乘级的复杂度。

根据冒泡排序我们可以知道交换相邻两个数可以做到这个数列的任何一个全排列,而这样的一个操作代价就是这个序列的逆序对数量。

所以我们直接枚举行的全排列和列的全排列即可(枚举全排列可以使用 std::next_permutation 实现)。

时间复杂度 \(O(H!W!)\)

代码

//the code is from chenjh
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
int n,m;
int a[10][10],b[10][10];
int c[10][10];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++)for(int j=0;j<m;j++) scanf("%d",&a[i][j]),c[i][j]=a[i][j];
	for(int i=0;i<n;i++)for(int j=0;j<m;j++) scanf("%d",&b[i][j]);
	int ans=-1;
	vector<int> v(n);//枚举行的全排列。
	for(int i=0;i<n;i++) v[i]=i;
	do{
		int now=0;
		for(int i=0;i<n;i++)for(int j=0;j<m;j++){
			c[v[i]][j]=a[i][j];
		}
		for(int i=0;i<n;i++)for(int j=i-1;j>=0;j--)now+=v[j]>v[i];//计算行的逆序对。
		vector<int> w(m);//枚举列的全排列。
		for(int i=0;i<m;i++) w[i]=i;
		int tmp=-1;
		do{
			bool sol=1;
			for(int i=0;i<n;i++)for(int j=0;j<m;j++)if(c[i][w[j]]!=b[i][j]){sol=0;break;}//判断操作后相等。
			if(sol){
				int ts=0;
				for(int i=0;i<m;i++)for(int j=i-1;j>=0;j--)ts+=w[j]>w[i];//计算列的逆序对。
				if(~tmp) tmp=min(tmp,ts);
				else tmp=ts;
			}
		}while(next_permutation(w.begin(),w.end()));
		if(~tmp){
			if(~ans) ans=min(ans,now+tmp);
			else ans=now+tmp;
		}
	}while(next_permutation(v.begin(),v.end()));
	printf("%d\n",ans);
	return 0;
}
posted @ 2024-01-20 11:48  Chen_Jinhui  阅读(41)  评论(0)    收藏  举报