【USACO题库】方块转换(c++,旋转,镜像操作)

文章介绍了一种解决正方形黑白瓦片图案转换问题的方法,通过枚举不同旋转和镜像操作,找出将原始图案转换为目标图案所需的最小步骤。
摘要由CSDN通过智能技术生成

题目描述

        一块N x N(1<=N<=10)正方形的黑白瓦片的图案要被转换成新的正方形图案。写一个程序来找出将原始图案按照以下列转换方法转换成新图案的最小方式:

#1:转90度:图案按顺时针转90度。

#2:转180度:图案按顺时针转180度。

#3:转270度:图案按顺时针转270度。

#4:反射:图案在水平方向翻转(形成原图案的镜像)。

#5:组合:图案在水平方向翻转,然后按照#1-#3之一转换。

#6:不改变:原图案不改变。

#7:无效转换:无法用以上方法得到新图案。

如果有多种可用的转换方法,请选择序号最小的那个。

输入

第一行: 单独的一个整数N。
第二行到第N+1行: N行每行N个字符(不是“@”就是“-”);这是转换前的正方形。
第N+2行到第2*N+1行: N行每行N个字符(不是“@”就是“-”);这是转换后的正方形。

输出

单独的一行包括1到7之间的一个数字(在上文已描述)表明需要将转换前的正方形变为转换后的正方形的转换方法。

样例输入
3
@-@
---
@@-
@-@
@--
--@
样例输出
1

看题目第一眼,感觉是dfs,有7种操作,是个难题

第二眼,这不就是水题吗,只有一次操作,那把每种操作枚举都用一遍就行了啊!那好,题解就写到这。

好吧,题目有两个算重要的知识点,一个是图案旋转,一个是图案镜像,OK,让我们往下看

图像旋转

下标 列\  行      1           2           3     
1@-@
2---
3@@-

上表二维数组 a   要将它顺时针旋转90°并保存到二维数组 b    下表为二维数组 b 的矩阵

下标 列 \ 行  1   2   3 
1a[3][1]a[2][1]a[1][1]
2a[3][2]a[2][2]a[1][2]
3a[3][3]a[2][3]a[1][3]

从表中可知,我们要是把下标换为 行 i j  ,那么 a[i][j] = a[n-j+1][i] ,这就是旋转图案的公式!

那将公式代入代码里面,见下

for(long long i=1;i<=n;i++)    //矩阵顺时针90°旋转
{
	for(long long j=1;j<=n;j++)
	{
		b[i][j]=a[n-j+1][i];
	}
}

图像镜像

下标 列\  行      1           2           3     
1@-@
2---
3@@-

上表又是二维数组 a   要将它镜像并保存到二维数组 b    下表为二维数组 b 的矩阵

下标 列 \ 行  1   2   3 
1a[1][3]a[1][2]a[1][3]
2a[2][3]a[2][2]a[2][1]
3a[3][3]a[3][2]a[3][1]

从表中可知,中间不变,两边互换,我们要是把下标换为 行 i j,那么互换就是 swap(a[i][j],a[i][n-j+1]) ,既然中间不变而且两边同时更新(互换),所以我们枚举每一个列时只用 枚举 n/2 次,这就是镜像的公式!

代码如下

for(long long i=1;i<=n;i++)    //把数先一一保存下来
{
	for(long long j=1;j<=n;j++)
	{
		b[i][j]=a[i][j];
	}
}
for(long long i=1;i<=n;i++)    //镜像操作
{
	for(long long j=1;j<=n/2;j++)
	{
		swap(b[i][j],b[i][n-j+1]);
	}
}

那好,现在旋转和镜像都弄完了,该把它们组合起来扔进题目里了,我们来翻译一下7种操作

#1:矩阵顺时针旋转90°

#2:矩阵顺时针旋转2个90°

#3:矩阵顺时针旋转3个90°

#4:镜像

#5:先镜像,然后代入 #1 ,#2 ,#3

#6:不改变,直接check 原矩阵是否等于目标矩阵

#7:输出7

OK,代码见下(详解请看注释)

#include<bits/stdc++.h>
using namespace std;
long long n;
char a[15][15],b[15][15],w[15][15],y[15][15],an[15][15];
bool check(char x[15][15])	//判断是否与目标矩阵相同 
{
	for(long long i=1;i<=n;i++)
	{
		for(long long j=1;j<=n;j++)
		{
			if(x[i][j]!=b[i][j])	return 0;
		}
	}
	return 1;
}
void _1_()	//#1操作 
{
	for(long long i=1;i<=n;i++)	//矩阵顺时针旋转90° 
	{
		for(long long j=1;j<=n;j++)
		{
			w[i][j]=a[n-j+1][i];
		}
	}
	if(check(w))	//判断 
	{
		cout<<1;
		exit(0);
	}
}
void _2_()	//#2操作 
{
	for(long long i=1;i<=n;i++)	//在#1的基础上再顺时针旋转90°,即旋转2个90° 
	{
		for(long long j=1;j<=n;j++)
		{
			a[i][j]=w[n-j+1][i];
		}
	}
	if(check(a))	//判断 
	{
		cout<<2;
		exit(0);
	}
}
void _3_()	//#3操作 
{
	for(long long i=1;i<=n;i++)	//在#2的基础上再顺时针旋转90°,即旋转3个90° 
	{
		for(long long j=1;j<=n;j++)
		{
			w[i][j]=a[n-j+1][i];
		}
	}
	if(check(w))	//判断 
	{
		cout<<3;
		exit(0);
	}
}
void _4_()	//#4操作 
{
	for(long long i=1;i<=n;i++)	//保存数据 
	{
		for(long long j=1;j<=n;j++)
		{
			y[i][j]=an[i][j];
		}
	}
	for(long long i=1;i<=n;i++)	//自身镜像操作 
	{
		for(long long j=1;j<=n/2;j++)
		{
			swap(y[i][j],y[i][n-j+1]);
		}
	}
	if(check(y))	//判断 
	{
		cout<<4;
		exit(0);
	}
} 
void _5_()	//#5操作 
{
	for(long long i=1;i<=n;i++)	//在#4的基础上顺时针旋转90°,即镜像后旋转90° 
	{
		for(long long j=1;j<=n;j++)
		{
			w[i][j]=y[n-j+1][i];
		}
	}
	if(check(w))	//判断 
	{
		cout<<5;
		exit(0);
	}
	for(long long i=1;i<=n;i++)	//在#4的基础上顺时针旋转180°,即镜像后旋转180° 
	{
		for(long long j=1;j<=n;j++)
		{
			y[i][j]=w[n-j+1][i];
		}
	}
	if(check(y))	//判断 
	{
		cout<<5;
		exit(0);
	}
	for(long long i=1;i<=n;i++)	//在#4的基础上顺时针旋转270°,即镜像后旋转270° 
	{
		for(long long j=1;j<=n;j++)
		{
			w[i][j]=y[n-j+1][i];
		}
	}
	if(check(w))	//判断 
	{
		cout<<5;
		exit(0);
	}
}
void _6_()	//#6操作 
{
	if(check(an))	//直接判断 现在的矩阵 是否与 目标矩阵 相同 
	{
		cout<<6;
		exit(0);
	}
}
void _7_()	//#7操作 
{
	cout<<7;	//eeeeeeeeee
	exit(0);
}
int main()
{
	cin>>n;
	for(long long i=1;i<=n;i++)	//输入矩阵 
	{
		for(long long j=1;j<=n;j++)
		{
			cin>>a[i][j];
            an[i][j]=a[i][j];    //保留原矩阵
		}
	}
	for(long long i=1;i<=n;i++)	//输入目标矩阵 
	{
		for(long long j=1;j<=n;j++)
		{
			cin>>b[i][j];
		}
	}
	_1_();	//序号小的在前 ,注意题目 
	_2_();
	_3_();
	_4_();
	_5_();
	_6_();
	_7_();
	return 0;
}

完结撒花!!!!!!!!!!!!!!!!!!!!!!!!

  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值