ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【例题3】虫食算

2021-07-12 21:35:56  阅读:191  来源: 互联网

标签:used return 食算 ++ number int 算式 例题


【例题3】虫食算

题面

题目描述

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

43#9865#045
+8468#6633
44445509678

其中 # 号表示被虫子啃掉的数字。根据算式,我们很容易判断:第一行的两个数字分别是 \(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\) 个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解。

输入格式

输入的第一行是一个整数 \(n\),代表进制数。

第二行到第四行,每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这 \(3\) 个字符串左右两端都没有空格。从左到右一次代表从高位到低位,并且恰好有 \(n\) 位。

输出格式

输出一行 \(n\) 个用空格隔开的整数,分别表示 \(A,B,...\) 代表的数字。

样例

样例输入

5
ABCED
BDACE
EBBAA

样例输出

1 0 3 4 2

数据范围与提示

对于 \(30\%\) 的数据,保证 \(n\leq 10\)。
对于 \(50\%\) 的数据,保证 \(n\leq 15\)。
对于 \(100\%\) 的数据,保证 \(1\leq n\leq 26\)。

分析
  • 首先,题意说明我们需要模拟运算流程,通过加法运算的流程正确性来判断是否成立。
  • 然后呢,没有然后了。
  • 本题可以爆搜,也可以用高斯消元(但是我不会)
  • 对于爆搜,可以枚举各个字母所代表的数字,在加上加法式子,从而得到答案。
  • 对于加法式子的判断,如果一列上的加数为 a,b,和为 c,进位数为 x,有如下几点
    • 如果进位数 x 是确定的,那么 \((a + b + x) \% n == c\).
    • 如果进位数 x 是不确定的,也就是 x 可能为 \(0\),也可能为 \(1\),那么 \((a+b)\%n==c\) 或者是 \((a + b + 1) \%n == c\).
    • 对于最高位,不仅要满足 \((a + b + c) \%n == c\) 而且要满足 \((a + b + c) / n ==0\).
  • 但是单纯这样的话会超时,所以我们枚举字母从式子的第 \(1\) 位到第 \(n\) 位的顺序来枚举,可以加快搜索的结束。
Code
#include <bits/stdc++.h>
using namespace std;

const int N = 30;

int n;
string s[3];
int s1[N], s2[N], s3[N];
int number[N];
int p[N], cnt;
bool vis[N], used[N];

bool check() {
	int x = 0;
	for (int i = n - 1; i >= 0; --i) {
		int a = number[s1[i]];
		int b = number[s2[i]];
		int c = number[s3[i]];
		
		if (a != -1 && b != -1 && c != -1) {
			if (x != -1) {
				if ((a + b + x) % n != c) 
					return false;
				if (!i && (a + b + x) / n != 0)
					return false;
				x = (a + b + x) / n;
			}
			else {
				if ((a + b) % n != c && (a + b + 1) % n != c)
					return false;
				if (!i && (a + b) / n != 0)
					return false;
			}
		}
		else x = -1;
	}
	return true;
}

bool dfs(int x) {
	if (x == cnt)
		return true;
	for (int i = 0; i < n; ++i) {
		if (!vis[i]) {
			number[p[x]] = i;
			vis[i] = true;
			if (check() && dfs(x + 1)) 
				return true;
			number[p[x]] = -1;
			vis[i] = false;
		}
	}
	return false;
}

int main(void) {
	memset(number, -1, sizeof(number));
	
	cin >> n;
	for (int i = 0; i < 3; ++i) cin >> s[i];
	
	for (int i = 0; i < n; ++i) {
		s1[i] = s[0][i] - 'A';
		s2[i] = s[1][i] - 'A';
		s3[i] = s[2][i] - 'A';
	}
	
	for (int i = n - 1; i >= 0; --i) {
		if (!used[s1[i]]) p[cnt++] = s1[i], used[s1[i]] = 1;
		if (!used[s2[i]]) p[cnt++] = s2[i], used[s2[i]] = 1;
		if (!used[s3[i]]) p[cnt++] = s3[i], used[s3[i]] = 1;
	}
	
	dfs(0);
	
	for (int i = 0; i < n; ++i)
		cout << number[i] << " ";
}

标签:used,return,食算,++,number,int,算式,例题
来源: https://www.cnblogs.com/Juro/p/15004009.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有