虫食算——DFS

目录

1.题目描述

2.题意

3.解题思路

4.代码实现


1.题目描述

所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。

来看一个简单的例子:

 43#9865#045
+  8468#6633
--------------
 44445506978

其中 # 号代表被虫子啃掉的数字。

根据算式,我们很容易判断:第一行的两个数字分别是 5 和 3,第二行的数字是 5。

现在,我们对问题做两个限制:

首先,我们只考虑加法的虫食算。这里的加法是 N 进制加法,算式中三个数都有 N 位,允许有前导的 0。

其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用相同的字母表示,不同的数字用不同的字母表示。

如果这个算式是 N 进制的,我们就取英文字母表的前 N 个大写字母来表示这个算式中的 0到 N−1 这 N 个不同的数字:但是这 N 个字母并不一定顺序地代表 0 到 N−1。

输入数据保证 N 个字母分别至少出现一次。

   BADC
+  CBDA
----------
   DCCC

上面的算式是一个 4 进制的算式。

很显然,我们只要让 ABCD 分别代表 0123,便可以让这个式子成立了。

你的任务是,对于给定的 N 进制加法算式,求出 N 个不同的字母分别代表的数字,使得该加法算式成立。

输入数据保证有且仅有一组解。

输入格式

输入包含 4 行。

第一行有一个正整数 N(N≤26)),后面的 3 行每行有一个由大写字母组成的字符串,分别代表两个加数以及和。

这 3 个字符串左右两端都没有空格,并且恰好有 N 位。

输出格式

输出包含一行。

在这一行中,应当包含唯一的那组解。

解是这样表示的:输出 N 个数字,分别表示 A,B,C……所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。

输入样例:

5
ABCED
BDACE
EBBAA

输出样例:

1 0 3 4 2

2.题意

题意:给你一个数字表示接下来的数字是几进制的数,再给你三行字符串表示两个数以及这两数相加的和,然后让你推测出,这些字符串中各个字符代表的数是多少,最后按字母A~Z的顺序输出对应字符代表的数。

3.解题思路

思路:先将由最后一列向第一列遍历,所遍历到的未存储过的字符先存储起来,然后通过DFS,每一步确定一个字符所对应的数字,每一步可以选择的数字为从0到n-1,如果选择当前字符再代入给出算式是合法的则可进入下一个字符的确定,否则返回,当全部的字符都确定,且合法后,DFS结束。

4.代码实现

str[3][]:存储输入的三行数字

n:表示进制数

q[]:存储由最后一列遍历到第一列先后n个不同的字符

path[]:存储这n个字符对应的数字

st[]:判断该数字是否使用过

代码思路:先将三个数当成字符串输入到str中,然后由最后一列开始,将每一个未存储的字符存入q[],然后初始化st[],和path[]。dfs(0),由第一个字符开始确定数字,可确定的数字由0枚举到n-1,如st[i]=false,则可以选择该数字,并将该数字加入到path[q[u]]中,然后判断这样赋值是否合法,若合法则dfs(t+1),进行下一个字符的确认。当全部字符确认后,dfs结束,输出path[]里,存储的各个字符对应的数字。

赋值是否合法,则由最后一列开始模拟第一行和第二行两数的计算,若每一列的模拟计算都正确,则合法,反之不合法。

#include<iostream>
#include<cstring>

using namespace std;

const int N = 30;
char str[3][N];
int n;
int q[N], path[N];
bool st[N];

bool check() {
	for (int i = n - 1, t = 0; i >= 0; i--) {///由最后一列开始,模拟计算
		int a = str[0][i] - 'A', b = str[1][i] - 'A', c = str[2][i] - 'A';
		if (path[a] != -1 && path[b] != -1 && path[c] != -1) {///三个数都有赋值,则按式子计算
			a = path[a], b = path[b], c = path[c];
			if (t != -1) {///若前一列计算出的余数确定,则直接计算
				/// 第一列的余数必须为零
				if ((a + b + t) % n != c || (i == 0 && (a + b + t) / n > 0))	return false;
				t = (a + b + t) / n;
			}
			else {///若前一列计算的余数不确定,则0,1都有可能,若两种带入式子都不行,则赋值错误
				if ((a + b + 0) % n != c && (a + b + 1) % n != c)	return false;
				if (i == 0 && (a + b) / n > 0)	return false;
			}
		}
		else t = -1;///若三个字符不是都赋值,则该列计算的余数不清楚,则让余数t=-1
	}
	return true;
}

bool dfs(int u) {

	if (u == n)	return ;
	for (int i = 0; i < n; i++) {
		if (!st[i]) {///判断该数字是否被使用
			st[i] = true;
			path[q[u]] = i;///给当前的第u个字符附值
			if (check() && dfs(u + 1))	return true;
			st[i] = false;
			path[q[u]] = -1;
		}
	}
	return false;
}

int main() {
	cin >> n;
	cin >> str[0] >> str[1] >> str[2];
	for (int i = n - 1, k = 0; i >= 0; i--) {
		for (int j = 0; j < 3; j++) {
			int t = str[j][i] - 'A';
			if (!st[t]) {///判断该字符是否被存储过
				st[t] = true;
				q[k++] = t;
			}
		}
	}
	memset(st, false, sizeof st);
	memset(path, -1, sizeof path);
	dfs(0);
	for (int i = 0; i < n; i++)	cout << path[i] << ' ';
	return 0;
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DFS深度优先搜索)可以用于解决迷宫出口问题。 首先,我们需要将迷宫转化为图,其中每个房间是图中的一个节点,每个房间之间的通道是图中的一条边。我们可以用一个二维数组来表示迷宫,其中0表示墙,1表示通道。 然后,我们可以使用DFS来搜索迷宫。我们从起点开始探索,每次选择一个未被访问的相邻节点进行探索,直到找到出口为止。为了避免陷入死循环,我们需要记录已经访问过的节点。 具体实现可以使用递归或者栈来实现DFS,以下是一个使用递归的示例代码(假设起点为(0,0),出口为(n-1,m-1)): ```python def dfs(x, y, visited, maze): # 判断当前节点是否为出口 if x == len(maze)-1 and y == len(maze[0])-1: return True # 标记当前节点已被访问 visited[x][y] = True # 搜索相邻节点 for dx, dy in [(0,1), (0,-1), (1,0), (-1,0)]: nx, ny = x+dx, y+dy # 判断相邻节点是否合法 if 0 <= nx < len(maze) and 0 <= ny < len(maze[0]) and maze[nx][ny] == 1 and not visited[nx][ny]: # 递归搜索相邻节点 if dfs(nx, ny, visited, maze): return True return False # 测试 maze = [ [1, 0, 1, 1, 1], [1, 0, 1, 0, 1], [1, 0, 1, 0, 1], [1, 1, 1, 0, 1], [0, 0, 0, 0, 1] ] visited = [[False for _ in range(len(maze[0]))] for _ in range(len(maze))] print(dfs(0, 0, visited, maze)) # 输出True,表示存在从起点到出口的路径 ``` 这段代码中,dfs函数的参数分别表示当前搜索的节点坐标、已经访问过的节点、迷宫的二维数组。搜索过程中,我们先判断当前节点是否为出口,如果是,则返回True。然后标记当前节点已被访问,并搜索相邻节点,如果找到了一个相邻节点可以到达出口,则返回True。否则,返回False表示无法到达出口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值