AtCoder - ABC 326 - D - ABC Puzzle (DFS)

看了很多题解都是写了一大坨,看起来非常的混乱,然而自己去写的时候又不可避免的写了一坨,只能尽可能的去优化代码可读性。


Time Limit: 4 sec / Memory Limit: 1024 MB

问题陈述

给你一个整数 N N N 和长度为 N N N 的字符串 R R R C C C ,它们由 A 、 B A、B AB C C C 组成。请解决下面的问题。

有一个 N × N N×N N×N 网格。所有单元格最初都是空的。您最多可以在每个单元格中写入 A 、 B A、B AB C C C 中的一个字符。(也可以让单元格为空)。

确定是否有可能满足以下所有条件,如果有可能,请打印一种满足这些条件的方法。

每一行和每一列正好包含一个 A、一个 B和一个 C。写入 i − t h i-th ith 行中最左边的字符与 R R R 中的 i − t h i-th ith 字符相匹配。写在 i − t h i -th ith 列中最顶端的字符与 C C C i − t h i -th ith 字符匹配。

限制因素

N N N 是介于 3 3 3 5 5 5 之间的整数,包括首尾两个整数。 R R R C C C 是长度为 N N N 的字符串,由 ABC组成。

输入

输入内容由标准输入法提供,格式如下

N
R
C

输出

如果无法填充网格以满足问题陈述中的条件,则单行打印 “No”。
否则,按以下格式打印一种填充网格的方法:

Yes
​A1
A2​ 
⋮
AN

第一行应包含 “是”。随后 N N N 行中的 i − t h i-th ith 应包含长度为 N N N 的字符串 A i A_i Ai​ 。

  • 如果 A i A_i Ai​ 的第 j j j 字符是 “.”,则表示从上往下 i − t h i-th ith 行和从左往右 j − t h j-th jth 列中的单元格为空。
  • 如果 A i A_i Ai 的第 j j j 个字符是 “A”,那么它表示 "A " 写在从上往下第 i i i 行、从左往上第 j j j 列的单元格中。
  • 如果 A i A_i Ai​ 的第 j j j 个字符是 “B”,那么它表示 "B "被写在从上往下第 i i i 行、从左往上第 j j j 列的单元格中。
  • 如果 A i A_i Ai​ 的第 j j j 个字符是 “C”,那么它表示 "C "被写在从上往下第 i i i 行、从左往上第 j j j 列的单元格中。

如果有多种正确的填充网格的方法,您可以打印其中任何一种。

Sample Input 1

5
ABCBC
ACAAB

Sample Output 1

Yes
AC..B
.BA.C
C.BA.
BA.C.
..CBA

对于这题4s的时间限制,并且联想到之前做过的八皇后问题,就想到可以用DFS来解决。

题目要求每行每列都只能有各一个 A , B , C A,B,C A,B,C 且都必须有这三个字母,我们可以以答案数组的层数同时作为dfs的层数,然后在搜到每一层的时候把这一层应有的 A , B , C A,B,C A,B,C 三个字母全部填上,这样我们就保证了每一行有且仅有一对 A , B , C A,B,C A,B,C 所以我们仅仅需要再判断一下每一列是否满足要求即可。
在这里就可以转化为八皇后模型了,开三个判断列的数组,每个对应一个字母,如果可以填就填上。

对于如何在一层里填上三个字母,我们需要一次性填上三个。
假如你写出了三层循环来找字母,那么你填出来之后就变成了一行只有一个字母了。
所以写出一个三层循环,每一层循环的是每个字母要填的位置,这里把重叠的位置全部continue掉。

代码:

#include<iostream>
#include<cstring>
#pragma warning(disable: 4996)
using namespace std;
const int N = 10;

int n;

char g[N][N];	//答案数组
char a[N];
char b[N];

//判断某一列是否已经有A或B或C
bool a_line[N];
bool b_line[N];
bool c_line[N];

//u代表的是层数,即答案数组的x轴
void dfs(int u) {

	if (u == n + 1) {	//如果搜满了所有层,就进行判断

		for (int i = 1; i <= n; i++) {		//第一次判断
			for (int j = 1; j <= n; j++) {	//判断最左边的字母是不是符合字符串A的顺序
				if (g[i][j] != '.') {
					if (g[i][j] == a[i])break;
					else return;
				}
				if (j == n && g[i][j] == '.')return;	//要是搜完了所有的甚至都没一个字母,直接跳
			}
		}

		for (int i = 1; i <= n; i++) {		//第二次判断
			for (int j = 1; j <= n; j++) {	//判断最上边的字母是不是符合字符串B的顺序
				if (g[j][i] != '.') {		//以下同理
					if (g[j][i] != b[i])return;
					else break;
				}
				if (j == n && g[j][i] == '.')return;
			}
		}
//-------------------------------------------------------------------------------------
		//输出答案
		cout << "Yes" << endl;
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				cout << g[i][j];
			}
			puts("");
		}
		exit(0);	//直接从这里终结整个程序
	}
//--------------------------------------------------------------------------------------
	//搜索部分
	//这里枚举的i,j,k是字母A,B,C填入的位置
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			if (i == j)continue;	//A和B不能填到一个位置,直接continue

			for (int k = 1; k <= n; k++) {
				if (i == k || j == k)continue;	//A和C,B和C不能填到一个位置

				if (!a_line[i] && !b_line[j] && !c_line[k]){//如果这一列还没有被填入过相应的字母

					g[u][i] = 'A', g[u][j] = 'B', g[u][k] = 'C';
					a_line[i] = b_line[j] = c_line[k] = 1;

					dfs(u + 1);//搜下一层

					//回溯状态
					g[u][i] = g[u][j] = g[u][k] = '.';
					a_line[i] = b_line[j] = c_line[k] = 0;
				}
			}
		}
	}
}
//----------------------------------------------------------------------------------------------
int main() {
	cin >> n;
	scanf("%s%s", a + 1, b + 1);

	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			g[i][j] = '.';
		}
	}

	dfs(1);
	//如果没找到答案就直接输出No
	cout << "No";

	return 0;
}
  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值