AtCoder Regular Contest 095 - E Symmetric Grid

本文介绍了一个编程挑战,目标是通过交换行和列使一个给定的字符矩阵变为对称矩阵。文章提供了详细的解决思路和算法实现,包括如何验证对称性和有效配对行与列的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

E - Symmetric Grid


Time limit : 2sec / Memory limit : 256MB

Score : 700 points

Problem Statement

There is an H×W grid (H vertical, W horizontal), where each square contains a lowercase English letter. Specifically, the letter in the square at the i-th row and j-th column is equal to the j-th character in the string Si.

Snuke can apply the following operation to this grid any number of times:

  • Choose two different rows and swap them. Or, choose two different columns and swap them.

Snuke wants this grid to be symmetric. That is, for any 1iH and 1jW, the letter in the square at the i-th row and j-th column and the letter in the square at the (H+1i)-th row and (W+1j)-th column should be equal.

Determine if Snuke can achieve this objective.

Constraints

  • 1H12
  • 1W12
  • |Si|=W
  • Si consists of lowercase English letters.

Input

Input is given from Standard Input in the following format:

H W
S1
S2
:
SH

Output

If Snuke can make the grid symmetric, print YES; if he cannot, print NO.


Sample Input 1

Copy
2 3
arc
rac

Sample Output 1

Copy
YES

If the second and third columns from the left are swapped, the grid becomes symmetric, as shown in the image below:


题意:

给你h*w的字符矩阵,你可以交换任意的行或者列。问你能不能使这个矩阵的每一个mp[i][j]=mp[h+1-i][w+1-j].


POINT:

遍历行的情况,然后判断列能不能合法。

swaped[i]=x代表。I行和x行配对。由于配对是两两的。所以情况数最多是11!!,而不是12!。

对于每一种行配对的情况,判断所有列能不能两两配对。

注意奇数的中间多出一列的情况。


英文题解:

E: Symmetric Grid

Notice that an operation about rows and an operation about columns are commutative. Thus, assume that we firstperform operations about rows, and then operations about columns.

Suppose that we finished operations about rows. How can we check if we can achieve a goal by operations aboutcolumns? Notice that, for each j = 1,2,...,W, the j-th column must be the reverse of the W + 1 j-th column. Inparticular, when W is odd, (W + 1)/2 is a palindrome.

Therefore, we can use the following method do check if we can achieve a goal by operations about columns:Initially, all rows are ”unused”.
Choose a particular unused row. Reverse it, and check if it matches with another unused row.

If it matches with another row, mark the two rows as ”used”.

Otherwise, if W is even, the answer is ”NO”. If W is odd and the current row is not a palindrome, theanswer is ”NO”. If W is odd and the current row is a palindrome, we should put it in the (W + 1)/2-throw. If this row is already filled, the answer is ”NO”.

It works in O(HW 2) time (or by binary search you can do it in O(HW log W ))
If we consider all H! possible orders of rows, it will be too slow. Instead, notice that only the set of pairs ((1,H)-th

rows, (2, H 1)-th rows, . . . ) matters. (In case H is odd, one row is left unpaired.)
Thus, we only need to try all pairings of rows. Since there are at most 11!! = 11
×9×7×5×3×1 = 10395 ways

of pairings, it’s fast enough. 



#include <stdio.h>
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
int n,m;
string s[20];
int swaped[20];
int used[20];
int ans = 0;
bool check()
{
	memset(used,0,sizeof used);
	for(int i=0;i<m;i++){
		for(int j=0;j<m;j++){
			if(used[i]||used[j]||i==j) continue;
			int cur=1;
			for(int k=0;k<n;k++){
				if(s[swaped[k]][i]!=s[k][j]){
					cur=0;
					break;
				}
			}
			if(cur){
				used[i]=used[j]=1;
			}
		}
	}
	int cnt=0,to=0;
	for(int i=0;i<m;i++){
		if(!used[i]){
			cnt++;to=i;
		}
	}
	if(cnt>=2||(m%2==0&&cnt)){
		return false;
	}
	if(!cnt) return true;
	for(int i=0;i<n;i++){
		if(s[swaped[i]][to]!=s[i][to]){
			return false;
		}
	}
	return true;
}


void dfs(int now,bool ji)
{
	if(now==(n+1)/2){
		if(check()){
			ans=1;
		}
		return;
	}
	for(int i=now;i<n;i++){
		for(int j=i+1;j<n;j++){
			if(swaped[i]==-1&&swaped[j]==-1){
				swaped[i]=j;
				swaped[j]=i;
				dfs(now+1,ji);
				swaped[i]=-1;
				swaped[j]=-1;
			}
		}
		if(ji&&swaped[i]==-1){
			swaped[i]=i;
			dfs(now+1,false);
			swaped[i]=-1;
		}
	}

}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		cin>>s[i];
		swaped[i]=-1;
	}
	if(n&1){
		dfs(0,true);
	}else{
		dfs(0,false);
	}
	if(ans) printf("YES\n");
	else printf("NO\n");
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值