该题有题解
时间限制:500MS 内存限制:65536K 提交次数:59 通过次数:21
题型: 编程题 语言: G++;GCC
16
题解:
可知每个字母变量分为相应长度的01变量,假设这种单位长度的01变量为单位变量。
总思路:将值必须是一样的单位变量放进同一个集合。(在等式的牵连下,某些单位变量的值要对应变化)
具体做法:
1.为每个单位变量分配一个空间(从2开始),存放其所属集合(由于等式中有0和1作为常量,所以也要为0和1分配空间,看其所属集合)。
2.首先是判断等式两边长度是否相等,若相等,则继续。
3.通过并查集,逐步为每个单位变量找到所属的集合,(期间如果发现常量1和常量0被要求在同一个集合,则不可能实现,直接退出)
4.遍历每一个单位变量(从0开始),统计集合数sum,则 ans = pow(2,sum-2) 减去2是因为常量0和常量1所在的集合的值已经确定了。
注意:代码等式可能只出现01的其中一个或不出现,那又减去2是否合法呢?不是应该出现几种常量才减去几吗? 其实在遍历单位变量找集合时,从0开始,已经假设两个变量都出现了,再减去它,不管有没有真的出现,都不影响答案。类似的好像叫做虚拟变量。
学习之处:将变量放到格子当中,通过下标与变量形成映射。
代码如下:
#include<cstdio>//scau 1138 代码等式 #include<cstring> #include<cstdlib> #include<cmath> int fa[10010],length[30],beg[30]; int find(int x) { return (x==fa[x]?x:find(fa[x])); } void Union(int m, int n)//这里可以优化,将深度大的合并到深度低的,这样查找速度会加快。用迭代。 { m = find(m); n = find(n); if(m!=n) fa[m] = n; } int main() { int n, s1[10010],s2[10010],len1 = 0,len2 = 0; scanf("%d",&n); scanf("%d",&length[0]); beg[0] = 2; for(int i = 1; i<n; i++)//为每个字母变量分配相应长度的单位变量,与此同时,每个单位变量都与数组的下标形成了一一对应的关系 { scanf("%d",&length[i]); beg[i] = beg[i-1] + length[i-1]; } char ch; getchar(); while((ch= getchar())!='=')//处理等式,将其转换成以单位变量为形式的串,并将串存到数组中,等待并查集 { if(ch=='0' || ch=='1') s1[len1++] = ch-'0'; else { for(int i = 0; i<length[ch-'a']; i++) s1[len1++] = beg[ch-'a'] + i; } } while((ch= getchar())!='\n') { if(ch=='0' || ch=='1') s2[len2++] = ch-'0'; else { for(int i = 0; i<length[ch-'a']; i++) s2[len2++] = beg[ch-'a'] + i; } } if(len1!=len2) { printf("0\n"); return 0; } for(int i = 0; i<beg[n-1]+length[n-1]; i++) //初始化每个单位变量的集合为自己 fa[i] = i; for(int i = 0; i<len1; i++)//并查集 { if(s1[i]+s2[i]==1) { printf("0\n"); return 0; } Union(s1[i],s2[i]); } int ans = 0; for(int i = 0; i<beg[n-1]+length[n-1]; i++)//遍历每个单位变量,统计集合个数 if(fa[i]==i) ans++; printf("%.0lf\n",pow(2,ans-2)); return 0; }
