湘大OJ 拼图 - XTUOJ


url: https://oj.xtu.edu.cn/problem.php?cid=1007&pid=3


拼图#

题目描述#

每一块拼图可以旋转,但是不能翻转(背面没图案);每个拼图有四条边,边有不同的形状。

我们用英文字母表示边的形状,如果两个拼图的边正好是对应的大小写,那么这两个拼图,就可以拼起来。

那么给你四块拼图,能否拼成一个2×2的拼图。

输入格式#

第一行是一个整数T (1≤T≤1000),表示测试用例的数量。

每个样例是四行,每行是四个字符组成的字符串,表示拼图按顺时钟的边的形状。

输出格式#

依次输出每个样例的结果,如果可以,输出“Yes”;否则输出“No”。

样例输入#

2

abab
ABaa
AAAA
aaaa

AAAA
BBBB
CCCC
DDDD

样例输出#

Yes
No

样例解释#

第一个样例,可以按

  A  |  b
A   A|a   a
  A  |  b
-----+------
  a  |  B 
a   a|A   a
  a  |  a

拼成。

解题思路:数据范围小,用回溯算法暴力遍历拼图块的顺序和方向。

#include <stdio.h>
#include <string.h>
int used[4];
char pieces[4][5];
char oc_pieces[4][5];

char trans(char c)
{
	return (c >= 'a' && c <= 'z') ? c - 32 : c + 32;
}

//void rotate(char oc_pieces[]) {
//    char t = oc_pieces[3];
//    for (int i = 3; i > 0; i--) {
//        oc_pieces[i] = oc_pieces[i - 1];
//    }
//    oc_pieces[0] = t;
//}

void rotate(char oc_pieces[])
{
	char t = oc_pieces[0];
	for (int i = 0; i < 3; i++)
	{
		oc_pieces[i] = oc_pieces[i + 1];
	}
	oc_pieces[3] = t;
}

int match()
{
	if (oc_pieces[0][1] == trans(oc_pieces[1][3]) &&
	        oc_pieces[1][2] == trans(oc_pieces[2][0]) &&
	        oc_pieces[2][3] == trans(oc_pieces[3][1]) &&
	        oc_pieces[3][0] == trans(oc_pieces[0][2]))
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

//check用于检查某个拼图块排列能否通过旋转拼图块拼上,可直接for循环,也可递归
int for_check()
{
	for (int i = 0; i < 4; i++)
	{
		rotate(oc_pieces[0]);
		for (int j = 0; j < 4; j++)
		{
			rotate(oc_pieces[1]);
			for (int k = 0; k < 4; k++)
			{
				rotate(oc_pieces[2]);
				for (int m = 0; m < 4; m++)
				{
					rotate(oc_pieces[3]);
					if (match())
					{
						return 1;
					}
				}
			}
		}
	}
	return 0;
}

//int dfs_check(int Idx)
//{
//	if (Idx == 4)
//	{
//		return match() ? 1 : 0;
//	}
//	for (int r = 0; r < 4; r++)
//	{
//		if (dfs_check(Idx + 1)) return 1;
//		rotate(oc_pieces[Idx]);
//	}
//	return 0;
//}

//通过回溯算法生成拼图块全排列,oc_pieces用于暂时存储order certain的拼图块。
int dfs(int deep)
{
	if (deep == 4)
	{
		return for_check();
//		return dfs_check(0);
	}

	for (int i = 0; i < 4; i++)
	{
		if (!used[i])
		{
			used[i] = 1;
			strcpy(oc_pieces[deep], pieces[i]);
			if (dfs(deep + 1)) return 1;
			used[i] = 0;
		}
	}
	return 0;
}

int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		memset(used, 0, sizeof(used));
		for (int i = 0; i < 4; i++)
		{
			scanf("%s", pieces[i]);
		}
		if (dfs(0)) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值