1138 代码等式
该题有题解
时间限制:500MS 内存限制:65536K
提交次数:59 通过次数:21
题型: 编程题 语言: C++;C
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
作者
admin
思路:题意要求左右两边位数相等且对应的位置的二进制相等。比如a=1b1,则a为1xx1,b等于a中的xx,类似于这样求有多少组变量。
一、将变量每一位用一个独立的数字代替,如a是4位,分别为2,3,4,5(0、1是题目已给出的),b是2位,分别为6,7等等;
二、检验两边位数是否相等,否则输出0结束,是则继续运行;
三、采用并查集,将两个独立数字合并为一个集合;
四、若0和1为一个集合,矛盾,输出0结束;
五、输出2的集合数-2次方(减2是因为0和1的集合是已知的数)。
代码
#include <stdio.h>
#include <string.h>
#include <math.h>
int c[10000];
int UF(int n1,int n2)
{
int i,r1,r2,f1,f2;
for(r1=0,f1=n1;c[f1]!=f1;f1=c[f1])
{
r1++;
}
for(r2=0,f2=n2;c[f2]!=f2;f2=c[f2])
{
r2++;
}
if(f1==f2)
{
return 0;
}
if(r1==0)//将深度较低的合并到深度高的
{
c[n1]=n2;
}
else
{
c[n2]=n1;
}
return 1;
}
int main()
{
int a[30],n,num1[10000],num2[10000],i,b[30],j,total,p1,p2,t;
char s[100];
scanf("%d",&n);
b[0]=2;//0、1占两位
scanf("%d",&a[0]);
for(i=1,total=2+a[0];i<n;i++)
{
b[i]=b[i-1]+a[i-1];//用于生成类似a=2、3、4、5的基数
scanf("%d",&a[i]);
total+=a[i];//统计总共有多少个数
}
scanf("%s",s);
for(i=0,p1=0,j=0;s[i]!='=';i++)//p1用于统计等号左边的位数
{
if(s[i]=='0')
{
p1++;
num1[j++]=0;
}
else if(s[i]=='1')
{
p1++;
num1[j++]=1;
}
else
{
p1+=a[s[i]-'a'];
for(t=0;j<p1;t++)
{
num1[j++]=b[s[i]-'a']+t;//num1用于生成a=2、3、4、5
}
}
}
for(i+=1,p2=0,j=0;i<strlen(s);i++)//p2用于统计等号右边的位数
{
if(s[i]=='0')
{
p2++;
num2[j++]=0;
}
else if(s[i]=='1')
{
p2++;
num2[j++]=1;
}
else
{
p2+=a[s[i]-'a'];
for(t=0;j<p2;t++)
{
num2[j++]=b[s[i]-'a']+t;
}
}
}
if(p1!=p2)//等号左右不想等就输出0
{
printf("0\n");
return 0;
}
for(i=0;i<total;i++)
{
c[i]=i;//用于并查集归类
}
for(i=0;i<p1;i++)
{
if((num1[i]==0&&num2[i]==1)||(num1[i]==1&&num2[i]==0))//0、1是已知的,如果为同一集合则矛盾
{
printf("0\n");
return 0;
}
else
{
if(UF(num1[i],num2[i]))
{
total--;//刚刚是统计有多少个数,现在是统计集合数
}
}
}
printf("%.0lf\n",pow(2,total-2));
}