c语言----移动n根火柴使等式成立

一、项目背景

近日在观看某短视频软件时,发现某些用户直播移动火柴游戏,笔者有时会很快找出方法,有时却毫无头绪,如5+7=9,怀疑无解,故以此编程。

二、编程环境

笔者用的是 Visual Studio 2019,基于标准库编程。

三、规则介绍

题目给出一个十位数以内的自然数加减算式,三个数都为0-9可用火柴表示的单个数字,如:

其中+-为:

                                                      

题目要求为移动一根火柴使原错误等式成立,如6-6=3,即可移动6上一根火柴,使6变为9,满足题意。

要求输入一个等式,输出满足题意的所有等式,若无,则输出无解。

四、思路解析

1、缺余量和移动数:

(1)定义;

       由于游戏中,三个数字和运算符号也可以移动,所以考察当将数字i变为j时,针对这个数字,火柴变动的最少个数即为移动数,而变动后所多余或所缺失的火柴数目为缺余量,定义正数为多余量,负数为缺失量。

        如:数字3变为数字9,至少需要移动1根火柴,而这一根火柴数字3没有,缺一根,故由3到9的变化中,移动数为1,缺余量为-1。

(2)数字火柴编码;

       为了计算缺余量和移动数,笔者将火柴数字图中七个火柴位置编码,由低位到高位如图,得到了从数字0到数字9的二进制数组:

int Num[10] = { 126,48,109,121,51,91,95,112,127,123 };

                                                  

        例如0,即为0b1111110,十进制为126。所以Num[i]就是数字i的火柴编码数。

(3)计算;

i变为j

缺失量=组成数字i的火柴数 - 组成数字j的火柴数。

data[i][j].suls = NumOfOne(Num[i]) - NumOfOne(Num[j]);

移动数=组成i,j火柴数较大的那个 - i,j公共火柴部分。

data[i][j].move = data[i][j].suls >= 0 ? (NumOfOne(Num[i]) - NumOfOne(Num[i] & Num[j])) : (NumOfOne(Num[j]) - NumOfOne(Num[i] & Num[j]));

其中NumOfOne()函数定义如下:

int NumOfOne(int n)
{
    int cnt;
    for (cnt = 0; n; cnt++)n = n & (n - 1);
    return cnt;
}

2、计算改变自身的移动数和多余量的和即为移动木柴数

此处做了算法的延伸,可解决移动多根火柴的问题。

bool Flag(num num1, num num2, num num3, num sym, int n) {
	//计算改变自身的移动数和多余量的和即为移动木柴数
	bool a = num1.suls + num2.suls + num3.suls + sym.suls == 0;
	num s[4] = { num1,num2,num3,sym };
	int sum = 0;
	for (int i = 0; i < 4; i++)
		if (s[i].suls >= 0)
			sum += s[i].move;
		else
			sum += s[i].move+s[i].suls;
	return a && (sum == n);
}

3、遍历计算

void cul(char* ch) {
	for (int i = 0; i < 10; i++)
		for (int j = 0; j < 10; j++)
			for (int k = 0; k < 10; k++)
				for (int l = 0; l < 2; l++)
					if (Flag(data[ch[0] - '0'][i], data[ch[2] - '0'][j], data[ch[4] - '0'][k], sym[(ch[1] / 2 - 21) * 2 + l], 1))
						if ((l && (i - j == k)) || ((!l) && (i + j == k)))
							printf("%d %c %d = %d\n", i, 43 + 2 * l, j, k);
}

五、代码

#include <iostream>
int Num[10] = { 126,48,109,121,51,91,95,112,127,123 };
struct num {
	int suls;
	int move;
}data[10][10], sym[4] = { {0,0},{1,1},{-1,1},{0,0} };
int NumOfOne(int n)
{
	int cnt;
	for (cnt = 0; n; cnt++)n = n & (n - 1);
	return cnt;
}
bool IfNumber(char ch) {
	return ch >= '0' && ch <= '9';
}
bool Flag(num num1, num num2, num num3, num sym, int n) {
	//计算改变自身的移动数和多余量的和即为移动木柴数
	bool a = num1.suls + num2.suls + num3.suls + sym.suls == 0;
	num s[4] = { num1,num2,num3,sym };
	int sum = 0;
	for (int i = 0; i < 4; i++)
		if (s[i].suls >= 0)
			sum += s[i].move;
		else
			sum += s[i].move+s[i].suls;
	return a && (sum == n);
}
void cul(char* ch) {
	for (int i = 0; i < 10; i++)
		for (int j = 0; j < 10; j++)
			for (int k = 0; k < 10; k++)
				for (int l = 0; l < 2; l++)
					if (Flag(data[ch[0] - '0'][i], data[ch[2] - '0'][j], data[ch[4] - '0'][k], sym[(ch[1] / 2 - 21) * 2 + l], 1))
						if ((l && (i - j == k)) || ((!l) && (i + j == k)))
							printf("%d %c %d = %d\n", i, 43 + 2 * l, j, k);
}
int main()
{
	char ch[10] = { 0 };
	for (int i = 0; i < 10; i++)
		for (int j = 0; j < 10; j++)
		{
			data[i][j].suls = NumOfOne(Num[i]) - NumOfOne(Num[j]);
			data[i][j].move = data[i][j].suls >= 0 ? (NumOfOne(Num[i]) - NumOfOne(Num[i] & Num[j])) : (NumOfOne(Num[j]) - NumOfOne(Num[i] & Num[j]));
		}
	while (1) {
		gets_s(ch);
		if (IfNumber(ch[0]) && (ch[1] == '+' || ch[1] == '-') && IfNumber(ch[2]) && ch[3] == '=' && IfNumber(ch[4]))
			cul(ch);
	}
}

六、总结:

最后测试5+7=9确实无解,短视频误人。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XiDelilA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值