火柴棒排列

题目描述

这是一个由火柴棒组成的等式,但它可能不正确。我们需要找到使等式正确所需的最少移动次数(如果有的话)

等式形式如下:

{数字}{操作}{数字} = {数字}

其中: [0 <= 数字<= 9] 且操作符只有 ‘-’ 和 ‘+’。

每个数字最多由7 根火柴棒组成,减号由 1根火柴棒组成,加号由 2 根火柴棒组成。

你每次可以将一根火柴棒从当前位置移动到另一个位置。只能在数字、加号和减号之间移动火柴棒,不能更改等号。

输入格式:

第一行是测试用例T的数量 。接下来的T行,每行包含一个等式。

输出格式:

对于每个测试用例,您需要输出使火柴棒等式成立所需的最小移动次数。如果等式本来就是正确的,则输出 0。如果等式怎么移动也无法正确,则输出-1。

输入样例:

3
9 - 1 = 4
5 + 1 = 5
1 + 1 = 1

输出样例:

1
1
-1

题解:

我使用了暴力枚举的方法,遍历了所有可能的 A、B、C 的组合,然后判断是否满足火柴棒的数量和等式的成立。

#include <bits/stdc++.h> // 这是一个包含了常用的 C++ 标准库头文件的头文件,可以简化代码的编写,但也可能增加编译的时间和内存消耗
using namespace std; // 这是一个命名空间的声明,可以让您在代码中直接使用标准库的名称,而不需要加上 std:: 前缀
int dic[] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6}; // 这是一个数组,存储了每个数字(0-9)需要的火柴棒的数量
int bian[7][10] = {{1, 0, 1, 1, 0, 1, 1, 1, 1, 1},{1, 1, 1, 1, 1, 0, 0, 1, 1, 1},
            {1, 1, 0, 1, 1, 1, 1, 1, 1, 1},{1, 0, 1, 1, 0, 1, 1, 0, 1, 1},
            {1, 0, 1, 0, 0, 0, 1, 0, 1, 0},{1, 0, 0, 0, 1, 1, 1, 0, 1, 1},
            {0, 0, 1, 1, 1, 1, 1, 0, 1, 1}}; // 这是一个二维数组,存储了每个数字(0-9)的火柴棒的分布情况,每一行代表一个数字,每一列代表一个火柴棒的位置,1 表示有火柴棒,0 表示没有火柴棒
int shu[10] = {126,48,109,121,51,91,95,112,127,123}; // 这是一个数组,存储了每个数字(0-9)的火柴棒的二进制表示,每一位代表一个火柴棒的位置,1 表示有火柴棒,0 表示没有火柴棒,从右往左数,第一位是最下面的火柴棒,第七位是最上面的火柴棒
int bu[10][10][2] = {{{20,19},{12,-1},{18,-1},{18,-1},{16,-1},{18,-1},{20,-1},{14,-1},{22,-1},{20,-1}},
{{12,11},{11,11},{14,-1},{13,-1},{13,-1},{15,-1},{13,-1},{14,-1},{17,-1},{-1,-1}},
{{18,17},{14,10},{16,17},{17,-1},{17,-1},{15,-1},{20,-1},{16,-1},{-1,-1},{-1,-1}},
{{18,17},{13,13},{17,13},{18,17},{14,-1},{19,-1},{19,-1},{-1,-1},{-1,-1},{-1,-1}},
{{16,15},{13,12},{17,15},{14,12},{17,15},{17,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}},
{{18,17},{15,12},{15,16},{19,16},{17,12},{-1,17},{-1,-1},{-1,-1},{-1,-1},{-1,-1}},
{{20,19},{13,14},{20,16},{19,17},{-1,16},{-1,14},{-1,19},{-1,-1},{-1,-1},{-1,-1}},
{{14,13},{14,12},{16,14},{-1,13},{-1,13},{-1,14},{-1,12},{-1,13},{-1,-1},{-1,-1}},
{{22,21},{17,13},{-1,19},{-1,18},{-1,16},{-1,18},{-1,19},{-1,13},{-1,21},{-1,-1}},
{{20,19},{-1,16},{-1,15},{-1,18},{-1,16},{-1,16},{-1,18},{-1,15},{-1,16},{-1,19}}}; // 这是一个三维数组,存储了每两个数字(0-9)之间可以构成的火柴棒的数量,每一层代表一个数字,每一行代表另一个数字,每一列代表一个运算符,0 表示加号,1 表示减号,-1 表示无法构成
//这个数据集里从10-22都有
int hch(int a,int b,int c,char fh){ // 这是一个函数,用于计算一个等式需要的火柴棒的数量,参数分别是 A、B、C 和运算符
    if(fh=='+') // 如果运算符是加号
        return dic[a]+dic[b]+dic[c]+2; // 返回 A、B、C 需要的火柴棒的数量之和,再加上两根火柴棒(加号和等号)
    else // 否则
        return dic[a]+dic[b]+dic[c]+1; // 返回 A、B、C 需要的火柴棒的数量之和,再加上一根火柴棒(减号和等号)
}
int ch(int a){ // 这是一个函数,用于计算一个数字的二进制表示中有多少个 1,参数是一个数字
    int c=0; // 定义一个变量 c,用于存储 1 的个数,初始为 0
    if(a>=1024){c+=1;a-=1024;} // 如果 a 大于等于 1024,说明最高位是 1,c 加 1,a 减去 1024
    if(a>=512){c+=1;a-=512;} // 如果 a 大于等于 512,说明次高位是 1,c 加 1,a 减去 512
    if(a>=256){c+=1;a-=256;} // 如果 a 大于等于 256,说明第三位是 1,c 加 1,a 减去 256
    if(a>=128){c+=1;a-=128;} // 如果 a 大于等于 128,说明第四位是 1,c 加 1,a 减去 128
    if(a>=64){c+=1;a-=64;} // 如果 a 大于等于 64,说明第五位是 1,c 加 1,a 减去 64
    if(a>=32){c+=1;a-=32;} // 如果 a 大于等于 32,说明第六位是 1,c 加 1,a 减去 32
    if(a>=16){c+=1;a-=16;} // 如果 a 大于等于 16,说明第七位是 1,c 加 1,a 减去 16
    if(a>=8){c+=1;a-=8;} // 如果 a 大于等于 8,说明第八位是 1,c 加 1,a 减去 8
    if(a>=4){c+=1;a-=4;} // 如果 a 大于等于 4,说明第九位是 1,c 加 1,a 减去 4
    if(a>=2){c+=1;a-=2;} // 如果 a 大于等于 2,说明第十位是 1,c 加 1,a 减去 2
    if(a>=1){c+=1;a-=1;} // 如果 a 大于等于 1,说明第十一位是 1,c 加 1,a 减去 1
    return c; // 返回 c,即 1 的个数
}


int main(){ // 这是主函数,程序的入口
    int n; // 定义一个变量 n,用于存储测试用例的数量
    cin>>n; // 从标准输入读取 n 的值
    for(int i=0;i<n;++i) // 使用一个 for 循环,从 0 到 n-1,遍历每个测试用例
    {
        int min = 100000; // 定义一个变量 min,用于存储最小的移动次数,初始为一个很大的数
        int a,b,c; // 定义三个变量 a、b、c,用于存储 A、B、C 的值
        char fh,dh; // 定义两个变量 fh、dh,用于存储运算符和等号
        cin>>a>>fh>>b>>dh>>c; // 从标准输入读取 a、fh、b、dh、c 的值
        int num = hch(a,b,c,fh); // 调用 hch 函数,计算等式需要的火柴棒的数量,赋值给 num
        if(num<=22&&num>=10){ // 如果 num 在 10 到 22 之间,说明等式是可能的
            for(int j = 0;j<10;j++){ // 使用一个 for 循环,从 0 到 9,遍历所有可能的 A 的值
                for(int k = 0;k<10;k++){ // 使用一个 for 循环,从 0 到 9,遍历所有可能的 B 的值
                    if(num == bu[j][k][0]&&(ch(shu[a]^shu[j])+ch(shu[b]^shu[k])+(fh!='+')+ch(shu[c]^shu[(j+k)]))<min){min = ch(shu[a]^shu[j])+ch(shu[b]^shu[k])+(fh!='+')+ch(shu[c]^shu[(j+k)]);} // 如果 num 等于 bu[j][k][0],说明 A + B = C 是可能的,然后计算 A、B、C 之间需要移动的火柴棒的数量,使用异或运算和 ch 函数,再加上运算符的变化,如果这个数量小于 min,就更新 min 的值
                    if(num == bu[j][k][1]&&(ch(shu[a]^shu[j])+ch(shu[b]^shu[k])+(fh!='-')+ch(shu[c]^shu[(j-k)]))<min){min = ch(shu[a]^shu[j])+ch(shu[b]^shu[k])+(fh!='-')+ch(shu[c]^shu[(j-k)]);} // 如果 num 等于 bu[j][k][1],说明 A - B = C 是可能的,然后计算 A、B、C 之间需要移动的火柴棒的数量,使用异或运算和 ch 函数,再加上运算符的变化,如果这个数量小于 min,就更新 min 的值
                }
            }
            cout<<min/2<<endl; // 输出 min 除以 2 的结果,因为每移动一根火柴棒,需要两次操作
        }
        else cout<<-1<<endl; // 否则,输出 -1,表示无法构成等式
    }
    return 0; // 返回 0,表示程序正常结束
}

当然,数组里的数据也可以通过代码计算得出。

这个用于计算出shu数组的内容:

     int b[10];
     for(int i = 0;i<10;i++){
         b[i]=0;
         for(int j = 0;j<7;j++){
             b[i]= b[i]*2+bian[j][i];
         }
         cout<<b[i]<<",";
     }

这个用于计算出bu数组的内容,并加上了大括号,可以直接把结果复制到代码中:

     cout<<"int b[10][10][2]={";
     for(int i = 0;i<10;i++){
         cout<<'{';
         for(int j = 0;j<10;j++){
             if(i+j>=0&&i+j<=9)cout<<'{'<<hch(i,j,i+j,'+')<<',';
             else cout<<"{-1,";
             if(i-j>=0&&i-j<=9)cout<<hch(i,j,i-j,'-')<<"},";
             else cout<<"-1},";
         }
         cout<<"},"<<endl;
     }
     cout<<"};";

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值