1138 代码等式[C]

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));
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值