SCAU 1138 代码等式
1138 代码等式
时间限制:500MS 内存限制:65536K
提交次数:59 通过次数:21
题型: 编程题 语言: 无限制
Description
一个代码等式就是形如x1x2...xi=y1y2...yj,这里xi和yj是二进制的数字(0或1)或者是一个变量(如英语中的小写字母)。每一个变量都是一个有固定长度的二进制代码。例如: a,b,c,d,e是变且它们的长度分别是4,2,4,4,2。考虑等式:1bad1=acbe,这个等式共有16组解。现要求任给一个等式,计算一共有多少组解。 (变量最多26个,长度和不超过10000)
输入格式
第一行数N为变量个数; 第二行N个数,为每个变量的位数 第三行为一个等式
输出格式
输出解的个数,无解输出0
输入样例
5 4 2 4 4 2 1bad1=acbe
输出样例
16
解题思路
题目意思:
代码由二进制数0,1和小写字母组成,其中字母代表若干个01二进制数,现在题目给你一个等式,等式也是有01和字母组成,然后告诉你用到字母的长度(二进制数的个数)根据等式判断满足等式的情况有多种
解题步骤:
个人的愚见一开始是用数组代表左右式子,根据字母的长度和已知的0和1分配到数组里,给每个数组里的元素记录信息,信息包括:所属的字母、在这个元素在字母中的排位,是否已经确认。前面两个信息是为了在接下来匹配等式两边的数时查找时要用到。而第三个信息点是为了在匹配当中和最后判断情况的时候用到确认这个元素是否是待定的。
开始时是以一个式子(默认为左式)为主式,从左到右扫,先根据已给的二进制扫,判断它的相同位置在副式(默认右式)中属于哪一个字母的那个位置,然后根据此查看牵动了多少其他元素的变动,变动主要分在这两个式子,所以我是分开判断,在此基础上,又开始在主和副式从左扫到右,根据情况再次变动,一直根据位置的变动判断元素的变动。最终停止的情况是找不到有相同所属字母和在字母中的排位(也就是一开始要存储得到前两点信息)
判断情况的时候是在上面的基础上进行的。也是手动将其中的元素变成已知。
#include<stdlib.h> #include<stdio.h> #include<string.h> #define MAXN 10010 typedef struct equation{ int value, row, column;// value指是否已确认该值,row指所属的字母,column指排在的位置 }equation; equation left[MAXN], right[MAXN]; char input[MAXN]; int num[26], m; int Transform(int cur, int kind) {//根据kind的值仅是判断当前改变的在左式还是右式子 int i, j, flag; if(kind == 1 && right[cur].value == 0) { for(i=0; i<m; i++) { if(right[i].row == right[cur].row && right[i].column == right[cur].column && right[i].value == 0) { right[i].value = 1; Transform(i, 0); } if(left[i].row == right[cur].row && left[i].column == right[cur].column && left[i].value == 0) { Transform(i, 0); } } } else if(kind == 0 && left[cur].value == 0) {//下面的两个if可以当做两个for使用,一个元素的改变牵动左右两条式子,这里要做的就是及时更新信息 for(i=0; i<m; ++i) { if(left[i].row == left[cur].row && left[i].column == left[cur].column && left[i].value == 0) { left[i].value = 1; Transform(i, 1); } if(right[i].row == left[cur].row && right[i].column == left[cur].column && right[i].value == 0) { Transform(i, 1); } } } return 1; } int Before(int cur) { int i; for(i=0; i<m; i++) { if(right[i].row == right[cur].row && right[i].column == right[cur].column && right[i].value == 0) { right[i].value = 1; Transform(i, 0); } if(left[i].row == right[cur].row && left[i].column == right[cur].column && left[i].value == 0) { Transform(i, 0); } } } int main() { // freopen("input.txt", "r", stdin); int i, j, n, len, flag, buffer, str_left, str_right, cur_num, ans = 1, k; scanf("%d", &n); for(i=0; i<n; ++i) scanf("%d", &num[i]); scanf("%s", input); len = strlen(input); flag = strchr(input, '=') - input; k = m = str_left = str_right = 0; for(i=0; i<flag; ++i) { if(input[i] != '0' && input[i] != '1') { buffer = input[i] - 'a'; m += num[buffer]; for(j=0; j<num[buffer]; ++j,++str_left) { left[str_left].value = 0; left[str_left].row = buffer; left[str_left].column = j; } } else { left[str_left].value = 1; left[str_left].row = left[str_left].column = -1; str_left++; m++; } } //前后的两个for循环都是初始化信息 for(i=flag+1; i<len; ++i) { if(input[i] != '0' && input[i] != '1') { buffer = input[i] - 'a'; k += num[buffer]; for(j=0; j<num[buffer]; ++j, ++str_right) { right[str_right].value = 0; right[str_right].row = buffer; right[str_right].column = j; } } else { left[str_right].value = 1; left[str_right].row = right[str_right].column = -1; str_right++; k++; } } if(k != m) {//左右两式子的个数都不相同则表示无解 printf("0\n"); return 0; } for(i=0; i<m; ++i) { if(left[i].row == left[i].column && left[i].row == -1) Transform(i, 1); if(right[i].row == right[i].column && right[i].row == -1) Transform(i, 0); } for(i=0; i<m; ++i) {//计算情况,before函数的作用就是为了模拟之前改动元素的情况,代码是直接复制的 if(left[i].value == 0) { ans *= 2; Before(i); } } for(i=0; i<m; ++i) { if(left[i].value != right[i].value) { printf("0\n"); return 0; } } printf("%d\n", ans); return 0; }
更多内容请关注个人微信公众号 物役记 (微信号:materialchains)
作者:雪影蓝枫
本文版权归作者和博客园共有,欢迎转载,未经作者同意须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。